From ae1b9ed5711e171ed196208bd484db4b775c407b Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Sun, 18 Aug 2024 17:27:08 +0300 Subject: [PATCH] veb: deprecate x.vweb in favor of veb; checker: show missing variants in the sumtype error --- .../cors/veb_cors_example.v} | 23 ++++++------ examples/{xvweb => veb}/todo/.gitignore | 0 examples/{xvweb => veb}/todo/README.md | 0 examples/{xvweb => veb}/todo/assets/main.css | 0 examples/{xvweb => veb}/todo/main.v | 24 ++++++------- .../{xvweb => veb}/todo/templates/index.html | 0 examples/vweb/static_website/server.v | 8 ++--- examples/vweb/veb_example.v | 1 + vlib/builtin/string.v | 8 +++++ vlib/v/ast/table.v | 7 ++-- vlib/v/ast/types.v | 32 +++++++++++++++-- vlib/v/checker/checker.v | 11 +++++- vlib/v/checker/errors.v | 1 + vlib/v/checker/fn.v | 36 +++++++++++++++++-- vlib/v/checker/if.v | 1 + vlib/v/checker/infix.v | 3 ++ .../tests/incorrect_smartcast2_err.out | 2 +- .../sum_type_common_fields_alias_error.out | 6 ++-- .../tests/sum_type_common_fields_error.out | 2 +- vlib/v/checker/tests/void_method_call.out | 4 +-- vlib/v/fmt/fmt.v | 2 +- vlib/v/gen/c/comptime.v | 4 +-- vlib/v/gen/c/fn.v | 19 ++++++++++ vlib/v/markused/markused.v | 1 + vlib/v/parser/fn.v | 10 ++++++ vlib/v/tests/skip_unused/x_vweb_run_at.vv | 8 ++--- vlib/x/sessions/tests/session_app_test.v | 18 +++++----- .../vweb2_middleware/vweb2_middleware.v | 6 ++-- vlib/x/vweb/vweb.v | 2 +- 29 files changed, 176 insertions(+), 63 deletions(-) rename examples/{xvweb/cors/vweb_cors_example.v => veb/cors/veb_cors_example.v} (77%) rename examples/{xvweb => veb}/todo/.gitignore (100%) rename examples/{xvweb => veb}/todo/README.md (100%) rename examples/{xvweb => veb}/todo/assets/main.css (100%) rename examples/{xvweb => veb}/todo/main.v (87%) rename examples/{xvweb => veb}/todo/templates/index.html (100%) diff --git a/examples/xvweb/cors/vweb_cors_example.v b/examples/veb/cors/veb_cors_example.v similarity index 77% rename from examples/xvweb/cors/vweb_cors_example.v rename to examples/veb/cors/veb_cors_example.v index b7d11da64a..7cd95c994e 100644 --- a/examples/xvweb/cors/vweb_cors_example.v +++ b/examples/veb/cors/veb_cors_example.v @@ -1,5 +1,5 @@ import time -import x.vweb +import veb // See https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS // and https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#preflighted_requests @@ -7,24 +7,26 @@ import x.vweb // > a server to indicate any origins (domain, scheme, or port) other than its own from // > which a browser should permit loading resources... -// Usage: do `./v run examples/xvweb/cors/` to start the app, +// Usage: do `./v run examples/xveb/cors/` to start the app, // then check the headers in another shell: // // 1) `curl -vvv -X OPTIONS http://localhost:45678/time` // 2) `curl -vvv -X POST http://localhost:45678/time` pub struct Context { - vweb.Context + veb.Context } pub struct App { - vweb.Middleware[Context] + veb.Middleware[Context] } // time is a simple POST request handler, that returns the current time. It should be available // to JS scripts, running on arbitrary other origins/domains. + +// pub fn (app &App) time() veb.Result { @[post] -pub fn (app &App) time(mut ctx Context) vweb.Result { +pub fn (app &App) time(mut ctx Context) veb.Result { return ctx.json({ 'time': time.now().format_ss_milli() }) @@ -32,9 +34,8 @@ pub fn (app &App) time(mut ctx Context) vweb.Result { fn main() { println(" -To test, if CORS works, copy this JS snippet, then go to for example https://stackoverflow.com/ , -press F12, then paste the snippet in the opened JS console. You should see the vweb server's time: - +To test, if CORS works, copy this JS snippet, then go to for example https://stackoverflow.com/ , +press F12, then paste the snippet in the opened JS console. You should see the veb server's time: var xhr = new XMLHttpRequest(); xhr.onload = function(data) { console.log('xhr loaded'); @@ -46,13 +47,13 @@ xhr.send(); mut app := &App{} - // use vweb's cors middleware to handle CORS requests - app.use(vweb.cors[Context](vweb.CorsOptions{ + // use veb's cors middleware to handle CORS requests + app.use(veb.cors[Context](veb.CorsOptions{ // allow CORS requests from every domain origins: ['*'] // allow CORS requests with the following request methods: allowed_methods: [.get, .head, .patch, .put, .post, .delete] })) - vweb.run[App, Context](mut app, 45678) + veb.run[App, Context](mut app, 45678) } diff --git a/examples/xvweb/todo/.gitignore b/examples/veb/todo/.gitignore similarity index 100% rename from examples/xvweb/todo/.gitignore rename to examples/veb/todo/.gitignore diff --git a/examples/xvweb/todo/README.md b/examples/veb/todo/README.md similarity index 100% rename from examples/xvweb/todo/README.md rename to examples/veb/todo/README.md diff --git a/examples/xvweb/todo/assets/main.css b/examples/veb/todo/assets/main.css similarity index 100% rename from examples/xvweb/todo/assets/main.css rename to examples/veb/todo/assets/main.css diff --git a/examples/xvweb/todo/main.v b/examples/veb/todo/main.v similarity index 87% rename from examples/xvweb/todo/main.v rename to examples/veb/todo/main.v index 081c2023e6..cf92396096 100644 --- a/examples/xvweb/todo/main.v +++ b/examples/veb/todo/main.v @@ -1,10 +1,10 @@ -// Simple TODO app using x.vweb +// Simple TODO app using veb // Run from this directory with `v run main.v` -// You can also enable vwebs livereload feature with -// `v watch -d vweb_livereload run main.v` +// You can also enable vebs livereload feature with +// `v watch -d veb_livereload run main.v` module main -import x.vweb +import veb import db.sqlite import os import time @@ -21,14 +21,14 @@ pub mut: } pub struct Context { - vweb.Context + veb.Context pub mut: // we can use this field to check whether we just created a TODO in our html templates created_todo bool } pub struct App { - vweb.StaticHandler + veb.StaticHandler pub: // we can access the SQLITE database directly via `app.db` db sqlite.DB @@ -36,16 +36,16 @@ pub: // This method will only handle GET requests to the index page @[get] -pub fn (app &App) index(mut ctx Context) vweb.Result { +pub fn (app &App) index(mut ctx Context) veb.Result { todos := sql app.db { select from Todo } or { return ctx.server_error('could not fetch todos from database!') } - return $vweb.html() + return $veb.html() } // This method will only handle POST requests to the index page @['/'; post] -pub fn (app &App) create_todo(mut ctx Context, name string) vweb.Result { +pub fn (app &App) create_todo(mut ctx Context, name string) veb.Result { // We can receive form input fields as arguments in a route! // we could also access the name field by doing `name := ctx.form['name']` @@ -78,7 +78,7 @@ pub fn (app &App) create_todo(mut ctx Context, name string) vweb.Result { } @['/todo/:id/complete'; post] -pub fn (app &App) complete_todo(mut ctx Context, id int) vweb.Result { +pub fn (app &App) complete_todo(mut ctx Context, id int) veb.Result { // first check if there exist a TODO record with `id` todos := sql app.db { select from Todo where id == id @@ -99,7 +99,7 @@ pub fn (app &App) complete_todo(mut ctx Context, id int) vweb.Result { } @['/todo/:id/delete'; post] -pub fn (app &App) delete_todo(mut ctx Context, id int) vweb.Result { +pub fn (app &App) delete_todo(mut ctx Context, id int) veb.Result { // first check if there exist a TODO record with `id` todos := sql app.db { select from Todo where id == id @@ -141,5 +141,5 @@ fn main() { }! // start our app at port 8080 - vweb.run[App, Context](mut app, 8080) + veb.run[App, Context](mut app, 8080) } diff --git a/examples/xvweb/todo/templates/index.html b/examples/veb/todo/templates/index.html similarity index 100% rename from examples/xvweb/todo/templates/index.html rename to examples/veb/todo/templates/index.html diff --git a/examples/vweb/static_website/server.v b/examples/vweb/static_website/server.v index 3ceeda4d26..90136298a4 100644 --- a/examples/vweb/static_website/server.v +++ b/examples/vweb/static_website/server.v @@ -1,14 +1,14 @@ module main -import x.vweb +import veb import os pub struct Context { - vweb.Context + veb.Context } pub struct App { - vweb.StaticHandler + veb.StaticHandler } fn main() { @@ -17,5 +17,5 @@ fn main() { os.chdir(os.dir(os.executable()))! mut app := &App{} app.handle_static('dist', true)! - vweb.run[App, Context](mut app, 8080) + veb.run[App, Context](mut app, 8080) } diff --git a/examples/vweb/veb_example.v b/examples/vweb/veb_example.v index b20df58067..1c030fd234 100644 --- a/examples/vweb/veb_example.v +++ b/examples/vweb/veb_example.v @@ -27,6 +27,7 @@ pub fn (app &App) before_request() { @['/users/:user'] pub fn (mut app App) user_endpoint(mut ctx Context, user string) veb.Result { + // pub fn (mut app App) user_endpoint(user string) veb.Result { id := rand.intn(100) or { 0 } return ctx.json({ user: id diff --git a/vlib/builtin/string.v b/vlib/builtin/string.v index b3beabcaed..3e5a815145 100644 --- a/vlib/builtin/string.v +++ b/vlib/builtin/string.v @@ -940,6 +940,14 @@ pub fn (s string) rsplit_once(delim string) ?(string, string) { return result[1], result[0] } +// split_n splits the string based on the passed `delim` substring. +// It returns the first Nth parts. When N=0, return all the splits. +// The last returned element has the remainder of the string, even if +// the remainder contains more `delim` substrings. +pub fn (s string) split_n(delim string, n int) []string { + return s.split_nth(delim, n) +} + // split_nth splits the string based on the passed `delim` substring. // It returns the first Nth parts. When N=0, return all the splits. // The last returned element has the remainder of the string, even if diff --git a/vlib/v/ast/table.v b/vlib/v/ast/table.v index d4430c40b2..84dcba1f5b 100644 --- a/vlib/v/ast/table.v +++ b/vlib/v/ast/table.v @@ -533,12 +533,11 @@ pub fn (t &Table) find_field(s &TypeSymbol, name string) !StructField { } SumType { t.resolve_common_sumtype_fields(mut ts) - if field := ts.info.find_field(name) { + if field := ts.info.find_sum_type_field(name) { return field } - // mut info := ts.info as SumType - // TODO: a more detailed error so that it's easier to fix? - return error('field `${name}` does not exist or have the same type in all sumtype variants') + missing_variants := t.find_missing_variants(ts.info, name) + return error('field `${name}` does not exist or have the same type in these sumtype `${ts.name}` variants: ${missing_variants}') } else {} } diff --git a/vlib/v/ast/types.v b/vlib/v/ast/types.v index 14ce93fa6d..4f47d16cf4 100644 --- a/vlib/v/ast/types.v +++ b/vlib/v/ast/types.v @@ -1748,7 +1748,7 @@ pub fn (t &TypeSymbol) find_field(name string) ?StructField { Aggregate { return t.info.find_field(name) } Struct { return t.info.find_field(name) } Interface { return t.info.find_field(name) } - SumType { return t.info.find_field(name) } + SumType { return t.info.find_sum_type_field(name) } else { return none } } } @@ -1811,7 +1811,7 @@ pub fn (s Struct) get_field(name string) StructField { panic('unknown field `${name}`') } -pub fn (s &SumType) find_field(name string) ?StructField { +pub fn (s &SumType) find_sum_type_field(name string) ?StructField { for mut field in unsafe { s.fields } { if field.name == name { return field @@ -1820,6 +1820,34 @@ pub fn (s &SumType) find_field(name string) ?StructField { return none } +// For the 'field does not exist or have the same type in all sumtype variants' error. +// To print all sumtype variants the developer has to fix. +pub fn (t &Table) find_missing_variants(s &SumType, field_name string) string { + mut res := []string{cap: 5} + for variant in s.variants { + ts := t.sym(variant) + if ts.kind != .struct_ { + continue + } + mut found := false + struct_info := ts.info as Struct + for field in struct_info.fields { + if field.name == field_name { + found = true + break + } + } + if !found { + res << ts.name + } + } + // println('!!!!! field_name=${field_name}') + // print_backtrace() + // println(res) + str := res.join(', ') + return str.replace("'", '`') +} + pub fn (i Interface) defines_method(name string) bool { if i.methods.any(it.name == name) { return true diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 3d330fed92..5851f6308a 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -953,7 +953,7 @@ fn (mut c Checker) fail_if_immutable(mut expr ast.Expr) (string, token.Pos) { } .sum_type { sumtype_info := typ_sym.info as ast.SumType - mut field_info := sumtype_info.find_field(expr.field_name) or { + mut field_info := sumtype_info.find_sum_type_field(expr.field_name) or { type_str := c.table.type_to_str(expr.expr_type) c.error('unknown field `${type_str}.${expr.field_name}`', expr.pos) return '', expr.pos @@ -1596,6 +1596,12 @@ fn (mut c Checker) selector_expr(mut node ast.SelectorExpr) ast.Type { node.from_embed_types = embed_types if sym.kind in [.aggregate, .sum_type] { unknown_field_msg = err.msg() + // TODO need a better way to check that we need to display sum type variants info + if unknown_field_msg.contains('does not exist or have the same type in all sumtype') { + info := sym.info as ast.SumType + missing_variants := c.table.find_missing_variants(info, field_name) + unknown_field_msg += missing_variants + } } } if !c.inside_unsafe { @@ -2598,6 +2604,9 @@ fn (mut c Checker) hash_stmt(mut node ast.HashStmt) { } fn (mut c Checker) import_stmt(node ast.Import) { + if node.mod == 'x.vweb' { + println('`x.vweb` is now `veb`. The module is no longer experimental. Simply `import veb` instead of `import x.vweb`.') + } c.check_valid_snake_case(node.alias, 'module alias', node.pos) for sym in node.syms { name := '${node.mod}.${sym.name}' diff --git a/vlib/v/checker/errors.v b/vlib/v/checker/errors.v index 24f718f0e7..92c85a3d7f 100644 --- a/vlib/v/checker/errors.v +++ b/vlib/v/checker/errors.v @@ -215,6 +215,7 @@ fn (mut c Checker) deprecate(kind string, name string, attrs []ast.Attr, pos tok c.warn(semicolonize('${start_message} has been deprecated since ${after_time.ymmdd()}, it will be an error after ${error_time.ymmdd()}', deprecation_message), pos) } else if after_time == now { + // print_backtrace() c.warn(semicolonize('${start_message} has been deprecated', deprecation_message), pos) // c.warn(semicolonize('${start_message} has been deprecated!11 m=${deprecation_message}', diff --git a/vlib/v/checker/fn.v b/vlib/v/checker/fn.v index f1ca9b7295..bcddea101f 100644 --- a/vlib/v/checker/fn.v +++ b/vlib/v/checker/fn.v @@ -433,6 +433,36 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) { } } c.fn_scope = node.scope + // Register implicit context var + typ_veb_result := c.table.find_type_idx('veb.Result') + if node.return_type == typ_veb_result { + typ_veb_context := c.table.find_type_idx('veb.Context') + // No `ctx` param? Add it + if !node.params.any(it.name == 'ctx') && node.params.len > 1 { + params := node.params.clone() + ctx_param := ast.Param{ + name: 'ctx' + typ: typ_veb_context + is_mut: true + } + node.params = [node.params[0], ctx_param] + node.params << params[1..] + println('new params ${node.name}') + // println(node.params) + } + // sym := c.table.sym(typ_veb_context) + // println('reging ${typ_veb_context} ${sym}') + // println(c.fn_scope) + // println(node.params) + c.fn_scope.register(ast.Var{ + name: 'ctx' + typ: typ_veb_context + pos: node.pos + is_used: true + is_mut: true + is_stack_obj: false // true + }) + } c.stmts(mut node.stmts) node_has_top_return := has_top_return(node.stmts) node.has_return = c.returns || node_has_top_return @@ -1058,6 +1088,7 @@ fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool) ast. } } + // XTODO document if typ != 0 { generic_vts := c.table.final_sym(typ) if generic_vts.info is ast.FnType { @@ -1902,7 +1933,7 @@ fn (mut c Checker) method_call(mut node ast.CallExpr) ast.Type { } left_type := c.expr(mut node.left) if left_type == ast.void_type { - c.error('cannot call a method using an invalid expression', node.pos) + // c.error('cannot call a method using an invalid expression', node.pos) return ast.void_type } c.expected_type = left_type @@ -2726,7 +2757,8 @@ fn (mut c Checker) post_process_generic_fns() ! { for concrete_types in gtypes { c.table.cur_concrete_types = concrete_types c.fn_decl(mut node) - if node.name in ['x.vweb.run', 'x.vweb.run_at', 'vweb.run', 'vweb.run_at'] { + if node.name in ['veb.run', 'veb.run_at', 'x.vweb.run', 'x.vweb.run_at', 'vweb.run', + 'vweb.run_at'] { for ct in concrete_types { if ct !in c.vweb_gen_types { c.vweb_gen_types << ct diff --git a/vlib/v/checker/if.v b/vlib/v/checker/if.v index 480318dee3..445e562a2a 100644 --- a/vlib/v/checker/if.v +++ b/vlib/v/checker/if.v @@ -67,6 +67,7 @@ fn (mut c Checker) if_expr(mut node ast.IfExpr) ast.Type { cond_typ := c.table.unaliased_type(c.unwrap_generic(c.expr(mut branch.cond))) if (cond_typ.idx() != ast.bool_type_idx || cond_typ.has_flag(.option) || cond_typ.has_flag(.result)) && !c.pref.translated && !c.file.is_translated { + //&& cond_typ.idx() != ast.void_type_idx { TODO bring back after the void split 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/infix.v b/vlib/v/checker/infix.v index 5f16baa95c..3a9b7f3615 100644 --- a/vlib/v/checker/infix.v +++ b/vlib/v/checker/infix.v @@ -799,9 +799,12 @@ fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type { } .and, .logical_or { if !c.pref.translated && !c.file.is_translated { + // TODO Bring back once I split void into void and bad + // if left_final_sym.kind !in [.bool, .void] { if left_final_sym.kind != .bool { c.error('left operand for `${node.op}` is not a boolean', node.left.pos()) } + // if right_final_sym.kind !in [.bool, .void] { if right_final_sym.kind != .bool { c.error('right operand for `${node.op}` is not a boolean', node.right.pos()) } diff --git a/vlib/v/checker/tests/incorrect_smartcast2_err.out b/vlib/v/checker/tests/incorrect_smartcast2_err.out index aa269b2911..aaf4ce9404 100644 --- a/vlib/v/checker/tests/incorrect_smartcast2_err.out +++ b/vlib/v/checker/tests/incorrect_smartcast2_err.out @@ -5,7 +5,7 @@ vlib/v/checker/tests/incorrect_smartcast2_err.vv:24:9: notice: smartcast can onl | ~~~ 25 | Left[int] { 26 | println(v[0].error) -vlib/v/checker/tests/incorrect_smartcast2_err.vv:26:17: error: field `error` does not exist or have the same type in all sumtype variants +vlib/v/checker/tests/incorrect_smartcast2_err.vv:26:17: error: field `error` does not exist or have the same type in these sumtype `Either[int, int]` variants: Right[int] 24 | match v[0] { 25 | Left[int] { 26 | println(v[0].error) diff --git a/vlib/v/checker/tests/sum_type_common_fields_alias_error.out b/vlib/v/checker/tests/sum_type_common_fields_alias_error.out index 79f268b3f9..bc36f75db4 100644 --- a/vlib/v/checker/tests/sum_type_common_fields_alias_error.out +++ b/vlib/v/checker/tests/sum_type_common_fields_alias_error.out @@ -1,4 +1,4 @@ -vlib/v/checker/tests/sum_type_common_fields_alias_error.vv:35:14: error: field `name` does not exist or have the same type in all sumtype variants +vlib/v/checker/tests/sum_type_common_fields_alias_error.vv:35:14: error: field `name` does not exist or have the same type in these sumtype `Main` variants: 33 | } 34 | println(m) 35 | assert m[0].name == 'abc' @@ -12,7 +12,7 @@ vlib/v/checker/tests/sum_type_common_fields_alias_error.vv:35:9: error: assert c | ~~~~~~~~~~~~~~~~~~ 36 | assert m[1].name == 'def' 37 | assert m[2].name == 'xyz' -vlib/v/checker/tests/sum_type_common_fields_alias_error.vv:36:14: error: field `name` does not exist or have the same type in all sumtype variants +vlib/v/checker/tests/sum_type_common_fields_alias_error.vv:36:14: error: field `name` does not exist or have the same type in these sumtype `Main` variants: 34 | println(m) 35 | assert m[0].name == 'abc' 36 | assert m[1].name == 'def' @@ -26,7 +26,7 @@ vlib/v/checker/tests/sum_type_common_fields_alias_error.vv:36:9: error: assert c | ~~~~~~~~~~~~~~~~~~ 37 | assert m[2].name == 'xyz' 38 | } -vlib/v/checker/tests/sum_type_common_fields_alias_error.vv:37:14: error: field `name` does not exist or have the same type in all sumtype variants +vlib/v/checker/tests/sum_type_common_fields_alias_error.vv:37:14: error: field `name` does not exist or have the same type in these sumtype `Main` variants: 35 | assert m[0].name == 'abc' 36 | assert m[1].name == 'def' 37 | assert m[2].name == 'xyz' diff --git a/vlib/v/checker/tests/sum_type_common_fields_error.out b/vlib/v/checker/tests/sum_type_common_fields_error.out index ec05ff5b74..dc3380ff2f 100644 --- a/vlib/v/checker/tests/sum_type_common_fields_error.out +++ b/vlib/v/checker/tests/sum_type_common_fields_error.out @@ -1,4 +1,4 @@ -vlib/v/checker/tests/sum_type_common_fields_error.vv:53:14: error: field `val` does not exist or have the same type in all sumtype variants +vlib/v/checker/tests/sum_type_common_fields_error.vv:53:14: error: field `val` does not exist or have the same type in these sumtype `Main` variants: 51 | assert m[2].name == '64bit integer' 52 | assert m[3].name == 'string' 53 | assert m[0].val == 123 diff --git a/vlib/v/checker/tests/void_method_call.out b/vlib/v/checker/tests/void_method_call.out index 1df2dae421..3c73ce16a9 100644 --- a/vlib/v/checker/tests/void_method_call.out +++ b/vlib/v/checker/tests/void_method_call.out @@ -1,5 +1,5 @@ -vlib/v/checker/tests/void_method_call.vv:5:17: error: cannot call a method using an invalid expression - 3 | +vlib/v/checker/tests/void_method_call.vv:5:17: cgen error: checker bug; CallExpr.left_type is 0 in method_call + 3 | 4 | fn main() { 5 | simple_fn().method() | ~~~~~~~~ diff --git a/vlib/v/fmt/fmt.v b/vlib/v/fmt/fmt.v index f1208a0369..ffa57ddc94 100644 --- a/vlib/v/fmt/fmt.v +++ b/vlib/v/fmt/fmt.v @@ -109,7 +109,7 @@ pub fn (f &Fmt) type_to_str_using_aliases(typ ast.Type, import_aliases map[strin println('${s}') } if s.starts_with('x.vweb') { - s = s.replace_once('x.vweb', 'veb.') + s = s.replace_once('x.vweb.', 'veb.') } return s } diff --git a/vlib/v/gen/c/comptime.v b/vlib/v/gen/c/comptime.v index 31c9f27d51..179d302f65 100644 --- a/vlib/v/gen/c/comptime.v +++ b/vlib/v/gen/c/comptime.v @@ -168,11 +168,11 @@ fn (mut g Gen) comptime_call(mut node ast.ComptimeCall) { } else { if !has_decompose { // do not generate anything if the argument lengths don't match - g.writeln('/* skipping ${sym.name}.${m.name} due to mismatched arguments list */') + g.writeln('/* skipping ${sym.name}.${m.name} due to mismatched arguments list: node.args=${node.args.len} m.params=${m.params.len} */') // g.writeln('println(_SLIT("skipping ${node.sym.name}.$m.name due to mismatched arguments list"));') // eprintln('info: skipping ${node.sym.name}.$m.name due to mismatched arguments list\n' + //'method.params: $m.params, args: $node.args\n\n') - // verror('expected ${m.params.len-1} arguments to method ${node.sym.name}.$m.name, but got $node.args.len') + // verror('expected ${m.params.len - 1} arguments to method ${node.sym.name}.${m.name}, but got ${node.args.len}') return } } diff --git a/vlib/v/gen/c/fn.v b/vlib/v/gen/c/fn.v index bbdfd09d41..e6ee6d8885 100644 --- a/vlib/v/gen/c/fn.v +++ b/vlib/v/gen/c/fn.v @@ -704,6 +704,20 @@ fn (mut g Gen) fn_decl_params(params []ast.Param, scope &ast.Scope, is_variadic // in C, `()` is untyped, unlike `(void)` g.write('void') } + /// mut is_implicit_ctx := false + // Veb actions defined by user can have implicit context + /* + if g.cur_fn != unsafe { nil } && g.cur_fn.is_method && g.cur_mod.name != 'veb' { + typ_veb_result := g.table.find_type_idx('veb.Result') + // if params.len == 3 { + // println(g.cur_fn) + //} + if g.cur_fn.return_type == typ_veb_result { + // is_implicit_ctx = true + g.write('/*veb*/') + } + } + */ for i, param in params { mut caname := if param.name == '_' { g.new_tmp_declaration_name() @@ -756,6 +770,11 @@ fn (mut g Gen) fn_decl_params(params []ast.Param, scope &ast.Scope, is_variadic g.write(', ') g.definitions.write_string(', ') } + + // if is_implicit_ctx && i == 0 && params[1].name != 'ctx' { + // g.writeln('veb__Context* ctx,') + // g.definitions.write_string('veb__Context* ctx,') + //} } if (g.pref.translated && is_variadic) || is_c_variadic { g.write(', ... ') diff --git a/vlib/v/markused/markused.v b/vlib/v/markused/markused.v index 17910c036e..07b4465473 100644 --- a/vlib/v/markused/markused.v +++ b/vlib/v/markused/markused.v @@ -306,6 +306,7 @@ pub fn mark_used(mut table ast.Table, mut pref_ pref.Preferences, ast_files []&a handle_vweb(mut table, mut all_fn_root_names, 'vweb.Result', 'vweb.filter', 'vweb.Context') handle_vweb(mut table, mut all_fn_root_names, 'x.vweb.Result', 'x.vweb.filter', 'x.vweb.Context') + handle_vweb(mut table, mut all_fn_root_names, 'veb.Result', 'veb.filter', 'veb.Context') // handle ORM drivers: orm_connection_implementations := table.iface_types['orm.Connection'] or { []ast.Type{} } diff --git a/vlib/v/parser/fn.v b/vlib/v/parser/fn.v index 7c94a129e9..dfef16f6ee 100644 --- a/vlib/v/parser/fn.v +++ b/vlib/v/parser/fn.v @@ -591,6 +591,16 @@ run them via `v file.v` instead', language: language }) } + /* + // Register implicit context var + p.scope.register(ast.Var{ + name: 'ctx' + typ: ast.error_type + pos: p.tok.pos() + is_used: true + is_stack_obj: true + }) + */ // Body p.cur_fn_name = name mut stmts := []ast.Stmt{} diff --git a/vlib/v/tests/skip_unused/x_vweb_run_at.vv b/vlib/v/tests/skip_unused/x_vweb_run_at.vv index 8508a26d2e..0c9fdfc311 100644 --- a/vlib/v/tests/skip_unused/x_vweb_run_at.vv +++ b/vlib/v/tests/skip_unused/x_vweb_run_at.vv @@ -1,10 +1,10 @@ -import x.vweb +import veb import time pub struct App {} pub struct Context { - vweb.Context + veb.Context } fn main() { @@ -15,10 +15,10 @@ fn main() { }() time.sleep(10 * time.second) mut app := &App{} - vweb.run_at[App, Context](mut app, port: 38090)! + veb.run_at[App, Context](mut app, port: 38090)! } @['/'] -pub fn (app &App) index(mut ctx Context) vweb.Result { +pub fn (app &App) index(mut ctx Context) veb.Result { return ctx.text('Hello World') } diff --git a/vlib/x/sessions/tests/session_app_test.v b/vlib/x/sessions/tests/session_app_test.v index fb62e1bda5..d6a685ff13 100644 --- a/vlib/x/sessions/tests/session_app_test.v +++ b/vlib/x/sessions/tests/session_app_test.v @@ -1,7 +1,7 @@ import net.http import time import x.sessions -import x.vweb +import veb import x.sessions.vweb2_middleware const port = 13010 @@ -24,12 +24,12 @@ const default_user = User{ } pub struct Context { - vweb.Context + veb.Context sessions.CurrentSession[User] } pub struct App { - vweb.Middleware[Context] + veb.Middleware[Context] pub mut: sessions &sessions.Sessions[User] started chan bool @@ -39,11 +39,11 @@ pub fn (mut app App) before_accept_loop() { app.started <- true } -pub fn (app &App) session_data(mut ctx Context) vweb.Result { +pub fn (app &App) session_data(mut ctx Context) veb.Result { return ctx.text(ctx.session_data.str()) } -pub fn (app &App) protected(mut ctx Context) vweb.Result { +pub fn (app &App) protected(mut ctx Context) veb.Result { if user := ctx.session_data { return ctx.json(user) } else { @@ -52,12 +52,12 @@ pub fn (app &App) protected(mut ctx Context) vweb.Result { } } -pub fn (mut app App) save_session(mut ctx Context) vweb.Result { +pub fn (mut app App) save_session(mut ctx Context) veb.Result { app.sessions.save(mut ctx, default_user) or { return ctx.server_error(err.msg()) } return ctx.ok('') } -pub fn (mut app App) update_session(mut ctx Context) vweb.Result { +pub fn (mut app App) update_session(mut ctx Context) veb.Result { if mut user := ctx.session_data { user.age++ app.sessions.save(mut ctx, user) or { return ctx.server_error(err.msg()) } @@ -72,7 +72,7 @@ pub fn (mut app App) update_session(mut ctx Context) vweb.Result { return ctx.ok('') } -pub fn (mut app App) destroy_session(mut ctx Context) vweb.Result { +pub fn (mut app App) destroy_session(mut ctx Context) veb.Result { app.sessions.destroy(mut ctx) or { return ctx.server_error(err.msg()) } // sessions module should also update the context assert ctx.session_data == none @@ -100,7 +100,7 @@ fn testsuite_begin() { app.use(vweb2_middleware.create[User, Context](mut app.sessions)) - spawn vweb.run_at[App, Context](mut app, port: port, timeout_in_seconds: 2) + spawn veb.run_at[App, Context](mut app, port: port, timeout_in_seconds: 2) // app startup time _ := <-app.started } diff --git a/vlib/x/sessions/vweb2_middleware/vweb2_middleware.v b/vlib/x/sessions/vweb2_middleware/vweb2_middleware.v index c4cb33649e..5f18b055d0 100644 --- a/vlib/x/sessions/vweb2_middleware/vweb2_middleware.v +++ b/vlib/x/sessions/vweb2_middleware/vweb2_middleware.v @@ -1,15 +1,15 @@ module vweb2_middleware import x.sessions -import x.vweb +import veb // middleware can be used to add session middleware to your vweb app to ensure // a valid session always exists. If a valid session exists the session data will // be loaded into `session_data`, else a new session id will be generated. // You have to pass the Context type as the generic type // Example: app.use(app.sessions.middleware[Context]()) -pub fn create[T, X](mut s sessions.Sessions[T]) vweb.MiddlewareOptions[X] { - return vweb.MiddlewareOptions[X]{ +pub fn create[T, X](mut s sessions.Sessions[T]) veb.MiddlewareOptions[X] { + return veb.MiddlewareOptions[X]{ handler: fn [mut s] [T, X](mut ctx X) bool { // a session id is retrieved from the client, so it must be considered // untrusted and has to be verified on every request diff --git a/vlib/x/vweb/vweb.v b/vlib/x/vweb/vweb.v index 23bf4bd355..787623970e 100644 --- a/vlib/x/vweb/vweb.v +++ b/vlib/x/vweb/vweb.v @@ -1,4 +1,4 @@ -//@[deprecated: '`x.vweb` is now `veb`. The module is no longer experimental.'] +@[deprecated: '`x.vweb` is now `veb`. The module is no longer experimental. Simply import veb instead of x.vweb'] module vweb import io