diff --git a/examples/veb/cors/veb_cors_example.v b/examples/veb/cors/veb_cors_example.v index 7cd95c994e..d5ca406152 100644 --- a/examples/veb/cors/veb_cors_example.v +++ b/examples/veb/cors/veb_cors_example.v @@ -24,9 +24,8 @@ pub struct App { // 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) veb.Result { +pub fn (app &App) time() veb.Result { return ctx.json({ 'time': time.now().format_ss_milli() }) @@ -34,7 +33,7 @@ pub fn (app &App) time(mut ctx Context) veb.Result { fn main() { println(" -To test, if CORS works, copy this JS snippet, then go to for example https://stackoverflow.com/ , +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) { diff --git a/examples/vweb/custom.html b/examples/veb/custom.html similarity index 100% rename from examples/vweb/custom.html rename to examples/veb/custom.html diff --git a/examples/vweb/footer.html b/examples/veb/footer.html similarity index 100% rename from examples/vweb/footer.html rename to examples/veb/footer.html diff --git a/examples/vweb/header.html b/examples/veb/header.html similarity index 100% rename from examples/vweb/header.html rename to examples/veb/header.html diff --git a/examples/vweb/index.html b/examples/veb/index.html similarity index 100% rename from examples/vweb/index.html rename to examples/veb/index.html diff --git a/examples/vweb/veb_example.v b/examples/veb/veb_example.v similarity index 96% rename from examples/vweb/veb_example.v rename to examples/veb/veb_example.v index 1c030fd234..6184b716a6 100644 --- a/examples/vweb/veb_example.v +++ b/examples/veb/veb_example.v @@ -34,7 +34,7 @@ pub fn (mut app App) user_endpoint(mut ctx Context, user string) veb.Result { }) } -pub fn (mut app App) index(mut ctx Context) veb.Result { +pub fn (mut app App) index() veb.Result { mut c := 0 lock app.state { app.state.cnt++ diff --git a/examples/vweb/vweb_example.v b/examples/vweb/vweb_example.v deleted file mode 100644 index e56a5f9104..0000000000 --- a/examples/vweb/vweb_example.v +++ /dev/null @@ -1,70 +0,0 @@ -module main - -import vweb -import rand - -const port = 8082 - -struct State { -mut: - cnt int -} - -struct App { - vweb.Context -mut: - state shared State -} - -pub fn (app &App) before_request() { - $if trace_before_request ? { - eprintln('[vweb] before_request: ${app.req.method} ${app.req.url}') - } -} - -@['/users/:user'] -pub fn (mut app App) user_endpoint(user string) vweb.Result { - id := rand.intn(100) or { 0 } - return app.json({ - user: id - }) -} - -pub fn (mut app App) index() vweb.Result { - mut c := 0 - lock app.state { - app.state.cnt++ - c = app.state.cnt - // - $if trace_address_of_app_state_cnt ? { - dump(ptr_str(app.state.cnt)) - } - } - show := true - hello := 'Hello world from vweb, request number: ${c}' - numbers := [1, 2, 3] - return $vweb.html() -} - -pub fn (mut app App) custom_template() vweb.Result { - return $vweb.html('custom.html') -} - -pub fn (mut app App) show_text() vweb.Result { - return app.text('Hello world from vweb') -} - -pub fn (mut app App) cookie() vweb.Result { - app.set_cookie(name: 'cookie', value: 'test') - return app.text('Response Headers\n${app.header}') -} - -@[post] -pub fn (mut app App) post() vweb.Result { - return app.text('Post body: ${app.req.data}') -} - -fn main() { - println('vweb example') - vweb.run(&App{}, port) -} diff --git a/vlib/v/ast/table.v b/vlib/v/ast/table.v index 17573128a4..c10222323b 100644 --- a/vlib/v/ast/table.v +++ b/vlib/v/ast/table.v @@ -30,7 +30,9 @@ pub mut: used_fns map[string]bool // filled in by the checker, when pref.skip_unused = true; used_consts map[string]bool // filled in by the checker, when pref.skip_unused = true; used_globals map[string]bool // filled in by the checker, when pref.skip_unused = true; - used_vweb_types []Type // vweb context types, filled in by checker, when pref.skip_unused = true; + used_veb_types []Type // veb context types, filled in by checker, when pref.skip_unused = true; + veb_res_idx_cache int // Cache of `veb.Result` type + veb_ctx_idx_cache int // Cache of `veb.Context` type used_maps int // how many times maps were used, filled in by checker, when pref.skip_unused = true; panic_handler FnPanicHandler = default_table_panic_handler panic_userdata voidptr = unsafe { nil } // can be used to pass arbitrary data to panic_handler; @@ -72,7 +74,7 @@ pub fn (mut t Table) free() { t.used_fns.free() t.used_consts.free() t.used_globals.free() - t.used_vweb_types.free() + t.used_veb_types.free() } } @@ -233,6 +235,16 @@ pub fn (mut t TypeSymbol) register_method(new_fn Fn) int { return t.methods.len - 1 } +pub fn (mut t TypeSymbol) update_method(f Fn) int { + for i, m in t.methods { + if m.name == f.name { + t.methods[i] = f + return i + } + } + return -1 +} + pub fn (t &Table) register_aggregate_method(mut sym TypeSymbol, name string) !Fn { if sym.kind != .aggregate { t.panic('table.register_aggregate_method: sym.name: ${sym.name}, sym.kind: ${sym.kind} is not an aggregate, name: ${name}') @@ -2550,3 +2562,12 @@ pub fn (t &Table) get_attrs(sym TypeSymbol) []Attr { } } } + +pub fn (mut t Table) get_veb_result_type_idx() int { + if t.veb_res_idx_cache > 0 { + return t.veb_res_idx_cache + } + + t.veb_res_idx_cache = t.find_type_idx('veb.Result') + return t.veb_res_idx_cache +} diff --git a/vlib/v/checker/comptime.v b/vlib/v/checker/comptime.v index 161c4f8c14..6b0fb8d569 100644 --- a/vlib/v/checker/comptime.v +++ b/vlib/v/checker/comptime.v @@ -616,7 +616,7 @@ fn (mut c Checker) verify_all_vweb_routes() { if c.vweb_gen_types.len == 0 { return } - c.table.used_vweb_types = c.vweb_gen_types + c.table.used_veb_types = c.vweb_gen_types typ_vweb_result := c.table.find_type_idx('vweb.Result') old_file := c.file for vgt in c.vweb_gen_types { diff --git a/vlib/v/checker/fn.v b/vlib/v/checker/fn.v index ce7b61c6c6..ccc26c0feb 100644 --- a/vlib/v/checker/fn.v +++ b/vlib/v/checker/fn.v @@ -434,11 +434,11 @@ 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') + typ_veb_result := c.table.get_veb_result_type_idx() // c.table.find_type_idx('veb.Result') if node.return_type == typ_veb_result { - typ_veb_context := c.table.find_type_idx('veb.Context') + typ_veb_context := ast.Type(u32(c.table.find_type_idx('veb.Context'))).set_nr_muls(1) // No `ctx` param? Add it - if !node.params.any(it.name == 'ctx') && node.params.len > 1 { + if !node.params.any(it.name == 'ctx') && node.params.len >= 1 { params := node.params.clone() ctx_param := ast.Param{ name: 'ctx' @@ -449,11 +449,19 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) { node.params << params[1..] // println('new params ${node.name}') // println(node.params) + // We've added ctx to the FnDecl node. + // Now update the existing method, already registered in Table. + mut rec_sym := c.table.sym(node.receiver.typ) + if mut m := c.table.find_method(rec_sym, node.name) { + m.params << ctx_param + rec_sym.update_method(m) + } } // sym := c.table.sym(typ_veb_context) // println('reging ${typ_veb_context} ${sym}') // println(c.fn_scope) // println(node.params) + // Finally add ctx to the scope c.fn_scope.register(ast.Var{ name: 'ctx' typ: typ_veb_context diff --git a/vlib/v/gen/c/comptime.v b/vlib/v/gen/c/comptime.v index 179d302f65..f29dc7825c 100644 --- a/vlib/v/gen/c/comptime.v +++ b/vlib/v/gen/c/comptime.v @@ -169,10 +169,27 @@ fn (mut g Gen) comptime_call(mut node ast.ComptimeCall) { 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: 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}') + // Adding a println(_SLIT(...)) like this breaks options + /* + g.writeln( + 'println(_SLIT("comptime: ${sym.name}.${m.name} has a mismatched arguments list.' + + ' The method has ${m.params.len - 1} parameters, but ${node.args.len} arguments were ' + + 'provided. \\nargs: ${node.args}\\n${g.file.path}:${node.pos.line_nr}"));') + */ + /* + if true { + println(node.args) + verror('comptime: ${sym.name}.${m.name} has a mismatched arguments list.' + + ' The method has ${m.params.len - 1} parameters, but ${node.args.len} arguments were ' + + 'provided. ${g.file.path}:${node.pos.line_nr}\n') + } + if true { + eprintln( + 'comptime: skipping ${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}') + } + */ return } } diff --git a/vlib/v/markused/markused.v b/vlib/v/markused/markused.v index 35e3859222..4bceadc7ff 100644 --- a/vlib/v/markused/markused.v +++ b/vlib/v/markused/markused.v @@ -449,7 +449,7 @@ fn handle_vweb(mut table ast.Table, mut all_fn_root_names []string, result_name all_fn_root_names << filter_name typ_vweb_context := ast.idx_to_type(table.find_type_idx(context_name)).set_nr_muls(1) all_fn_root_names << '${int(typ_vweb_context)}.html' - for vgt in table.used_vweb_types { + for vgt in table.used_veb_types { sym_app := table.sym(vgt) for m in sym_app.methods { mut skip := true diff --git a/vlib/veb/veb.v b/vlib/veb/veb.v index 41be14c2f7..d1cc5af6ca 100644 --- a/vlib/veb/veb.v +++ b/vlib/veb/veb.v @@ -223,6 +223,8 @@ fn ev_callback[A, X](mut pv picoev.Picoev, fd int, events int) { $if trace_picoev_callback ? { eprintln('> read event on file descriptor ${fd}') } + // TODO figure out the POST repeat in ev_callback + // println('ev_callback fd=${fd} params.routes=${params.routes.len}') handle_read[A, X](mut pv, mut params, fd) } else { // should never happen @@ -323,7 +325,7 @@ fn handle_write_string(mut pv picoev.Picoev, mut params RequestParams, fd int) { // handle_read reads data from the connection and if the request is complete // it calls `handle_route` and closes the connection. -// If the request is not complete it stores the incomplete request in `params` +// If the request is not complete, it stores the incomplete request in `params` // and the connection stays open until it is ready to read again @[direct_array_access; manualfree] fn handle_read[A, X](mut pv picoev.Picoev, mut params RequestParams, fd int) { @@ -592,6 +594,7 @@ fn handle_request[A, X](mut conn net.TcpConn, req http.Request, params &RequestP } fn handle_route[A, X](mut app A, mut user_context X, url urllib.URL, host string, routes &map[string]Route) { + // println('\n\nHANDLE ROUTE') mut route := Route{} mut middleware_has_sent_response := false mut not_found := false @@ -771,6 +774,7 @@ fn handle_route[A, X](mut app A, mut user_context X, url urllib.URL, host string } fn route_matches(url_words []string, route_words []string) ?[]string { + // println('route_matches(url_words:${url_words} route_words:${route_words}') // URL path should be at least as long as the route path // except for the catchall route (`/:path...`) if route_words.len == 1 && route_words[0].starts_with(':') && route_words[0].ends_with('...') {