mirror of
https://github.com/vlang/v.git
synced 2025-09-11 08:25:42 -04:00
veb: deprecate x.vweb in favor of veb; checker: show missing variants in the sumtype error
This commit is contained in:
parent
ceac4baf87
commit
ae1b9ed571
@ -1,5 +1,5 @@
|
|||||||
import time
|
import time
|
||||||
import x.vweb
|
import veb
|
||||||
|
|
||||||
// See https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
|
// See https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
|
||||||
// and https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#preflighted_requests
|
// 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
|
// > a server to indicate any origins (domain, scheme, or port) other than its own from
|
||||||
// > which a browser should permit loading resources...
|
// > 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:
|
// then check the headers in another shell:
|
||||||
//
|
//
|
||||||
// 1) `curl -vvv -X OPTIONS http://localhost:45678/time`
|
// 1) `curl -vvv -X OPTIONS http://localhost:45678/time`
|
||||||
// 2) `curl -vvv -X POST http://localhost:45678/time`
|
// 2) `curl -vvv -X POST http://localhost:45678/time`
|
||||||
|
|
||||||
pub struct Context {
|
pub struct Context {
|
||||||
vweb.Context
|
veb.Context
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct App {
|
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
|
// 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.
|
// to JS scripts, running on arbitrary other origins/domains.
|
||||||
|
|
||||||
|
// pub fn (app &App) time() veb.Result {
|
||||||
@[post]
|
@[post]
|
||||||
pub fn (app &App) time(mut ctx Context) vweb.Result {
|
pub fn (app &App) time(mut ctx Context) veb.Result {
|
||||||
return ctx.json({
|
return ctx.json({
|
||||||
'time': time.now().format_ss_milli()
|
'time': time.now().format_ss_milli()
|
||||||
})
|
})
|
||||||
@ -32,9 +34,8 @@ pub fn (app &App) time(mut ctx Context) vweb.Result {
|
|||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
println("
|
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 vweb server's time:
|
press F12, then paste the snippet in the opened JS console. You should see the veb server's time:
|
||||||
|
|
||||||
var xhr = new XMLHttpRequest();
|
var xhr = new XMLHttpRequest();
|
||||||
xhr.onload = function(data) {
|
xhr.onload = function(data) {
|
||||||
console.log('xhr loaded');
|
console.log('xhr loaded');
|
||||||
@ -46,13 +47,13 @@ xhr.send();
|
|||||||
|
|
||||||
mut app := &App{}
|
mut app := &App{}
|
||||||
|
|
||||||
// use vweb's cors middleware to handle CORS requests
|
// use veb's cors middleware to handle CORS requests
|
||||||
app.use(vweb.cors[Context](vweb.CorsOptions{
|
app.use(veb.cors[Context](veb.CorsOptions{
|
||||||
// allow CORS requests from every domain
|
// allow CORS requests from every domain
|
||||||
origins: ['*']
|
origins: ['*']
|
||||||
// allow CORS requests with the following request methods:
|
// allow CORS requests with the following request methods:
|
||||||
allowed_methods: [.get, .head, .patch, .put, .post, .delete]
|
allowed_methods: [.get, .head, .patch, .put, .post, .delete]
|
||||||
}))
|
}))
|
||||||
|
|
||||||
vweb.run[App, Context](mut app, 45678)
|
veb.run[App, Context](mut app, 45678)
|
||||||
}
|
}
|
@ -1,10 +1,10 @@
|
|||||||
// Simple TODO app using x.vweb
|
// Simple TODO app using veb
|
||||||
// Run from this directory with `v run main.v`
|
// Run from this directory with `v run main.v`
|
||||||
// You can also enable vwebs livereload feature with
|
// You can also enable vebs livereload feature with
|
||||||
// `v watch -d vweb_livereload run main.v`
|
// `v watch -d veb_livereload run main.v`
|
||||||
module main
|
module main
|
||||||
|
|
||||||
import x.vweb
|
import veb
|
||||||
import db.sqlite
|
import db.sqlite
|
||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
@ -21,14 +21,14 @@ pub mut:
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct Context {
|
pub struct Context {
|
||||||
vweb.Context
|
veb.Context
|
||||||
pub mut:
|
pub mut:
|
||||||
// we can use this field to check whether we just created a TODO in our html templates
|
// we can use this field to check whether we just created a TODO in our html templates
|
||||||
created_todo bool
|
created_todo bool
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct App {
|
pub struct App {
|
||||||
vweb.StaticHandler
|
veb.StaticHandler
|
||||||
pub:
|
pub:
|
||||||
// we can access the SQLITE database directly via `app.db`
|
// we can access the SQLITE database directly via `app.db`
|
||||||
db sqlite.DB
|
db sqlite.DB
|
||||||
@ -36,16 +36,16 @@ pub:
|
|||||||
|
|
||||||
// This method will only handle GET requests to the index page
|
// This method will only handle GET requests to the index page
|
||||||
@[get]
|
@[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 {
|
todos := sql app.db {
|
||||||
select from Todo
|
select from Todo
|
||||||
} or { return ctx.server_error('could not fetch todos from database!') }
|
} 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
|
// This method will only handle POST requests to the index page
|
||||||
@['/'; post]
|
@['/'; 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 can receive form input fields as arguments in a route!
|
||||||
// we could also access the name field by doing `name := ctx.form['name']`
|
// 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]
|
@['/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`
|
// first check if there exist a TODO record with `id`
|
||||||
todos := sql app.db {
|
todos := sql app.db {
|
||||||
select from Todo where id == id
|
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]
|
@['/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`
|
// first check if there exist a TODO record with `id`
|
||||||
todos := sql app.db {
|
todos := sql app.db {
|
||||||
select from Todo where id == id
|
select from Todo where id == id
|
||||||
@ -141,5 +141,5 @@ fn main() {
|
|||||||
}!
|
}!
|
||||||
|
|
||||||
// start our app at port 8080
|
// start our app at port 8080
|
||||||
vweb.run[App, Context](mut app, 8080)
|
veb.run[App, Context](mut app, 8080)
|
||||||
}
|
}
|
@ -1,14 +1,14 @@
|
|||||||
module main
|
module main
|
||||||
|
|
||||||
import x.vweb
|
import veb
|
||||||
import os
|
import os
|
||||||
|
|
||||||
pub struct Context {
|
pub struct Context {
|
||||||
vweb.Context
|
veb.Context
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct App {
|
pub struct App {
|
||||||
vweb.StaticHandler
|
veb.StaticHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
@ -17,5 +17,5 @@ fn main() {
|
|||||||
os.chdir(os.dir(os.executable()))!
|
os.chdir(os.dir(os.executable()))!
|
||||||
mut app := &App{}
|
mut app := &App{}
|
||||||
app.handle_static('dist', true)!
|
app.handle_static('dist', true)!
|
||||||
vweb.run[App, Context](mut app, 8080)
|
veb.run[App, Context](mut app, 8080)
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,7 @@ pub fn (app &App) before_request() {
|
|||||||
|
|
||||||
@['/users/:user']
|
@['/users/:user']
|
||||||
pub fn (mut app App) user_endpoint(mut ctx Context, user string) veb.Result {
|
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 }
|
id := rand.intn(100) or { 0 }
|
||||||
return ctx.json({
|
return ctx.json({
|
||||||
user: id
|
user: id
|
||||||
|
@ -940,6 +940,14 @@ pub fn (s string) rsplit_once(delim string) ?(string, string) {
|
|||||||
return result[1], result[0]
|
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.
|
// split_nth splits the string based on the passed `delim` substring.
|
||||||
// It returns the first Nth parts. When N=0, return all the splits.
|
// 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 last returned element has the remainder of the string, even if
|
||||||
|
@ -533,12 +533,11 @@ pub fn (t &Table) find_field(s &TypeSymbol, name string) !StructField {
|
|||||||
}
|
}
|
||||||
SumType {
|
SumType {
|
||||||
t.resolve_common_sumtype_fields(mut ts)
|
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
|
return field
|
||||||
}
|
}
|
||||||
// mut info := ts.info as SumType
|
missing_variants := t.find_missing_variants(ts.info, name)
|
||||||
// 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 these sumtype `${ts.name}` variants: ${missing_variants}')
|
||||||
return error('field `${name}` does not exist or have the same type in all sumtype variants')
|
|
||||||
}
|
}
|
||||||
else {}
|
else {}
|
||||||
}
|
}
|
||||||
|
@ -1748,7 +1748,7 @@ pub fn (t &TypeSymbol) find_field(name string) ?StructField {
|
|||||||
Aggregate { return t.info.find_field(name) }
|
Aggregate { return t.info.find_field(name) }
|
||||||
Struct { return t.info.find_field(name) }
|
Struct { return t.info.find_field(name) }
|
||||||
Interface { 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 }
|
else { return none }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1811,7 +1811,7 @@ pub fn (s Struct) get_field(name string) StructField {
|
|||||||
panic('unknown field `${name}`')
|
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 } {
|
for mut field in unsafe { s.fields } {
|
||||||
if field.name == name {
|
if field.name == name {
|
||||||
return field
|
return field
|
||||||
@ -1820,6 +1820,34 @@ pub fn (s &SumType) find_field(name string) ?StructField {
|
|||||||
return none
|
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 {
|
pub fn (i Interface) defines_method(name string) bool {
|
||||||
if i.methods.any(it.name == name) {
|
if i.methods.any(it.name == name) {
|
||||||
return true
|
return true
|
||||||
|
@ -953,7 +953,7 @@ fn (mut c Checker) fail_if_immutable(mut expr ast.Expr) (string, token.Pos) {
|
|||||||
}
|
}
|
||||||
.sum_type {
|
.sum_type {
|
||||||
sumtype_info := typ_sym.info as ast.SumType
|
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)
|
type_str := c.table.type_to_str(expr.expr_type)
|
||||||
c.error('unknown field `${type_str}.${expr.field_name}`', expr.pos)
|
c.error('unknown field `${type_str}.${expr.field_name}`', expr.pos)
|
||||||
return '', 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
|
node.from_embed_types = embed_types
|
||||||
if sym.kind in [.aggregate, .sum_type] {
|
if sym.kind in [.aggregate, .sum_type] {
|
||||||
unknown_field_msg = err.msg()
|
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 {
|
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) {
|
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)
|
c.check_valid_snake_case(node.alias, 'module alias', node.pos)
|
||||||
for sym in node.syms {
|
for sym in node.syms {
|
||||||
name := '${node.mod}.${sym.name}'
|
name := '${node.mod}.${sym.name}'
|
||||||
|
@ -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()}',
|
c.warn(semicolonize('${start_message} has been deprecated since ${after_time.ymmdd()}, it will be an error after ${error_time.ymmdd()}',
|
||||||
deprecation_message), pos)
|
deprecation_message), pos)
|
||||||
} else if after_time == now {
|
} else if after_time == now {
|
||||||
|
// print_backtrace()
|
||||||
c.warn(semicolonize('${start_message} has been deprecated', deprecation_message),
|
c.warn(semicolonize('${start_message} has been deprecated', deprecation_message),
|
||||||
pos)
|
pos)
|
||||||
// c.warn(semicolonize('${start_message} has been deprecated!11 m=${deprecation_message}',
|
// c.warn(semicolonize('${start_message} has been deprecated!11 m=${deprecation_message}',
|
||||||
|
@ -433,6 +433,36 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
c.fn_scope = node.scope
|
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)
|
c.stmts(mut node.stmts)
|
||||||
node_has_top_return := has_top_return(node.stmts)
|
node_has_top_return := has_top_return(node.stmts)
|
||||||
node.has_return = c.returns || node_has_top_return
|
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 {
|
if typ != 0 {
|
||||||
generic_vts := c.table.final_sym(typ)
|
generic_vts := c.table.final_sym(typ)
|
||||||
if generic_vts.info is ast.FnType {
|
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)
|
left_type := c.expr(mut node.left)
|
||||||
if left_type == ast.void_type {
|
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
|
return ast.void_type
|
||||||
}
|
}
|
||||||
c.expected_type = left_type
|
c.expected_type = left_type
|
||||||
@ -2726,7 +2757,8 @@ fn (mut c Checker) post_process_generic_fns() ! {
|
|||||||
for concrete_types in gtypes {
|
for concrete_types in gtypes {
|
||||||
c.table.cur_concrete_types = concrete_types
|
c.table.cur_concrete_types = concrete_types
|
||||||
c.fn_decl(mut node)
|
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 {
|
for ct in concrete_types {
|
||||||
if ct !in c.vweb_gen_types {
|
if ct !in c.vweb_gen_types {
|
||||||
c.vweb_gen_types << ct
|
c.vweb_gen_types << ct
|
||||||
|
@ -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)))
|
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)
|
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.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',
|
c.error('non-bool type `${c.table.type_to_str(cond_typ)}` used as if condition',
|
||||||
branch.cond.pos())
|
branch.cond.pos())
|
||||||
}
|
}
|
||||||
|
@ -799,9 +799,12 @@ fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type {
|
|||||||
}
|
}
|
||||||
.and, .logical_or {
|
.and, .logical_or {
|
||||||
if !c.pref.translated && !c.file.is_translated {
|
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 {
|
if left_final_sym.kind != .bool {
|
||||||
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())
|
||||||
}
|
}
|
||||||
|
// if right_final_sym.kind !in [.bool, .void] {
|
||||||
if right_final_sym.kind != .bool {
|
if right_final_sym.kind != .bool {
|
||||||
c.error('right operand for `${node.op}` is not a boolean', node.right.pos())
|
c.error('right operand for `${node.op}` is not a boolean', node.right.pos())
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ vlib/v/checker/tests/incorrect_smartcast2_err.vv:24:9: notice: smartcast can onl
|
|||||||
| ~~~
|
| ~~~
|
||||||
25 | Left[int] {
|
25 | Left[int] {
|
||||||
26 | println(v[0].error)
|
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] {
|
24 | match v[0] {
|
||||||
25 | Left[int] {
|
25 | Left[int] {
|
||||||
26 | println(v[0].error)
|
26 | println(v[0].error)
|
||||||
|
@ -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 | }
|
33 | }
|
||||||
34 | println(m)
|
34 | println(m)
|
||||||
35 | assert m[0].name == 'abc'
|
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'
|
36 | assert m[1].name == 'def'
|
||||||
37 | assert m[2].name == 'xyz'
|
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)
|
34 | println(m)
|
||||||
35 | assert m[0].name == 'abc'
|
35 | assert m[0].name == 'abc'
|
||||||
36 | assert m[1].name == 'def'
|
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'
|
37 | assert m[2].name == 'xyz'
|
||||||
38 | }
|
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'
|
35 | assert m[0].name == 'abc'
|
||||||
36 | assert m[1].name == 'def'
|
36 | assert m[1].name == 'def'
|
||||||
37 | assert m[2].name == 'xyz'
|
37 | assert m[2].name == 'xyz'
|
||||||
|
@ -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'
|
51 | assert m[2].name == '64bit integer'
|
||||||
52 | assert m[3].name == 'string'
|
52 | assert m[3].name == 'string'
|
||||||
53 | assert m[0].val == 123
|
53 | assert m[0].val == 123
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
vlib/v/checker/tests/void_method_call.vv:5:17: error: cannot call a method using an invalid expression
|
vlib/v/checker/tests/void_method_call.vv:5:17: cgen error: checker bug; CallExpr.left_type is 0 in method_call
|
||||||
3 |
|
3 |
|
||||||
4 | fn main() {
|
4 | fn main() {
|
||||||
5 | simple_fn().method()
|
5 | simple_fn().method()
|
||||||
| ~~~~~~~~
|
| ~~~~~~~~
|
||||||
|
@ -109,7 +109,7 @@ pub fn (f &Fmt) type_to_str_using_aliases(typ ast.Type, import_aliases map[strin
|
|||||||
println('${s}')
|
println('${s}')
|
||||||
}
|
}
|
||||||
if s.starts_with('x.vweb') {
|
if s.starts_with('x.vweb') {
|
||||||
s = s.replace_once('x.vweb', 'veb.')
|
s = s.replace_once('x.vweb.', 'veb.')
|
||||||
}
|
}
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
@ -168,11 +168,11 @@ fn (mut g Gen) comptime_call(mut node ast.ComptimeCall) {
|
|||||||
} else {
|
} else {
|
||||||
if !has_decompose {
|
if !has_decompose {
|
||||||
// do not generate anything if the argument lengths don't match
|
// 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"));')
|
// 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' +
|
// eprintln('info: skipping ${node.sym.name}.$m.name due to mismatched arguments list\n' +
|
||||||
//'method.params: $m.params, args: $node.args\n\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
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)`
|
// in C, `()` is untyped, unlike `(void)`
|
||||||
g.write('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 {
|
for i, param in params {
|
||||||
mut caname := if param.name == '_' {
|
mut caname := if param.name == '_' {
|
||||||
g.new_tmp_declaration_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.write(', ')
|
||||||
g.definitions.write_string(', ')
|
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 {
|
if (g.pref.translated && is_variadic) || is_c_variadic {
|
||||||
g.write(', ... ')
|
g.write(', ... ')
|
||||||
|
@ -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, '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, '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:
|
// handle ORM drivers:
|
||||||
orm_connection_implementations := table.iface_types['orm.Connection'] or { []ast.Type{} }
|
orm_connection_implementations := table.iface_types['orm.Connection'] or { []ast.Type{} }
|
||||||
|
@ -591,6 +591,16 @@ run them via `v file.v` instead',
|
|||||||
language: language
|
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
|
// Body
|
||||||
p.cur_fn_name = name
|
p.cur_fn_name = name
|
||||||
mut stmts := []ast.Stmt{}
|
mut stmts := []ast.Stmt{}
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import x.vweb
|
import veb
|
||||||
import time
|
import time
|
||||||
|
|
||||||
pub struct App {}
|
pub struct App {}
|
||||||
|
|
||||||
pub struct Context {
|
pub struct Context {
|
||||||
vweb.Context
|
veb.Context
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
@ -15,10 +15,10 @@ fn main() {
|
|||||||
}()
|
}()
|
||||||
time.sleep(10 * time.second)
|
time.sleep(10 * time.second)
|
||||||
mut app := &App{}
|
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')
|
return ctx.text('Hello World')
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import net.http
|
import net.http
|
||||||
import time
|
import time
|
||||||
import x.sessions
|
import x.sessions
|
||||||
import x.vweb
|
import veb
|
||||||
import x.sessions.vweb2_middleware
|
import x.sessions.vweb2_middleware
|
||||||
|
|
||||||
const port = 13010
|
const port = 13010
|
||||||
@ -24,12 +24,12 @@ const default_user = User{
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct Context {
|
pub struct Context {
|
||||||
vweb.Context
|
veb.Context
|
||||||
sessions.CurrentSession[User]
|
sessions.CurrentSession[User]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct App {
|
pub struct App {
|
||||||
vweb.Middleware[Context]
|
veb.Middleware[Context]
|
||||||
pub mut:
|
pub mut:
|
||||||
sessions &sessions.Sessions[User]
|
sessions &sessions.Sessions[User]
|
||||||
started chan bool
|
started chan bool
|
||||||
@ -39,11 +39,11 @@ pub fn (mut app App) before_accept_loop() {
|
|||||||
app.started <- true
|
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())
|
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 {
|
if user := ctx.session_data {
|
||||||
return ctx.json(user)
|
return ctx.json(user)
|
||||||
} else {
|
} 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()) }
|
app.sessions.save(mut ctx, default_user) or { return ctx.server_error(err.msg()) }
|
||||||
return ctx.ok('')
|
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 {
|
if mut user := ctx.session_data {
|
||||||
user.age++
|
user.age++
|
||||||
app.sessions.save(mut ctx, user) or { return ctx.server_error(err.msg()) }
|
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('')
|
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()) }
|
app.sessions.destroy(mut ctx) or { return ctx.server_error(err.msg()) }
|
||||||
// sessions module should also update the context
|
// sessions module should also update the context
|
||||||
assert ctx.session_data == none
|
assert ctx.session_data == none
|
||||||
@ -100,7 +100,7 @@ fn testsuite_begin() {
|
|||||||
|
|
||||||
app.use(vweb2_middleware.create[User, Context](mut app.sessions))
|
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 startup time
|
||||||
_ := <-app.started
|
_ := <-app.started
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
module vweb2_middleware
|
module vweb2_middleware
|
||||||
|
|
||||||
import x.sessions
|
import x.sessions
|
||||||
import x.vweb
|
import veb
|
||||||
|
|
||||||
// middleware can be used to add session middleware to your vweb app to ensure
|
// 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
|
// 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.
|
// be loaded into `session_data`, else a new session id will be generated.
|
||||||
// You have to pass the Context type as the generic type
|
// You have to pass the Context type as the generic type
|
||||||
// Example: app.use(app.sessions.middleware[Context]())
|
// Example: app.use(app.sessions.middleware[Context]())
|
||||||
pub fn create[T, X](mut s sessions.Sessions[T]) vweb.MiddlewareOptions[X] {
|
pub fn create[T, X](mut s sessions.Sessions[T]) veb.MiddlewareOptions[X] {
|
||||||
return vweb.MiddlewareOptions[X]{
|
return veb.MiddlewareOptions[X]{
|
||||||
handler: fn [mut s] [T, X](mut ctx X) bool {
|
handler: fn [mut s] [T, X](mut ctx X) bool {
|
||||||
// a session id is retrieved from the client, so it must be considered
|
// a session id is retrieved from the client, so it must be considered
|
||||||
// untrusted and has to be verified on every request
|
// untrusted and has to be verified on every request
|
||||||
|
@ -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
|
module vweb
|
||||||
|
|
||||||
import io
|
import io
|
||||||
|
Loading…
x
Reference in New Issue
Block a user