From b7175b54ebd932ec30c4100ada39c89418a0762f Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Fri, 3 Jul 2020 15:10:39 +0200 Subject: [PATCH] vweb: ['/:arg1/:arg2/action'] attribute --- vlib/builtin/builtin.v | 6 +++ vlib/v/ast/ast.v | 83 ++++++++++++++++++-------------- vlib/v/checker/checker.v | 40 ++++++++------- vlib/v/fmt/fmt.v | 1 + vlib/v/gen/cgen.v | 14 ++++-- vlib/v/gen/comptime.v | 55 +++++++++++++++++++++ vlib/v/gen/js/js.v | 2 + vlib/v/parser/comptime.v | 48 +++++++++++++++--- vlib/v/parser/fn.v | 1 + vlib/v/parser/parser.v | 43 ++++++++++------- vlib/v/table/table.v | 5 +- vlib/v/tests/comptime_for_test.v | 27 +++++++++++ vlib/vweb/vweb.v | 56 ++++++++++++++++----- 13 files changed, 281 insertions(+), 100 deletions(-) create mode 100644 vlib/v/tests/comptime_for_test.v diff --git a/vlib/builtin/builtin.v b/vlib/builtin/builtin.v index 5c243da67d..7cbcb6fb1f 100644 --- a/vlib/builtin/builtin.v +++ b/vlib/builtin/builtin.v @@ -249,3 +249,9 @@ fn __print_assert_failure(i &VAssertMetaInfo) { } } } + +pub struct MethodAttr { +pub: + value string + method string +} diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index 90659f2a5a..a734b88b96 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -15,10 +15,10 @@ pub type Expr = AnonFn | ArrayInit | AsCast | Assoc | BoolLiteral | CallExpr | C ParExpr | PostfixExpr | PrefixExpr | RangeExpr | SelectorExpr | SizeOf | SqlExpr | StringInterLiteral | StringLiteral | StructInit | Type | TypeOf -pub type Stmt = AssertStmt | AssignStmt | Attr | Block | BranchStmt | Comment | CompIf | - ConstDecl | DeferStmt | EnumDecl | ExprStmt | FnDecl | ForCStmt | ForInStmt | ForStmt | - GlobalDecl | GoStmt | GotoLabel | GotoStmt | HashStmt | Import | InterfaceDecl | Module | - Return | SqlStmt | StructDecl | TypeDecl | UnsafeStmt +pub type Stmt = AssertStmt | AssignStmt | Attr | Block | BranchStmt | Comment | CompFor | + CompIf | ConstDecl | DeferStmt | EnumDecl | ExprStmt | FnDecl | ForCStmt | ForInStmt | + ForStmt | GlobalDecl | GoStmt | GotoLabel | GotoStmt | HashStmt | Import | InterfaceDecl | + Module | Return | SqlStmt | StructDecl | TypeDecl | UnsafeStmt pub type ScopeObject = ConstField | GlobalDecl | Var @@ -457,11 +457,11 @@ pub mut: pub struct MatchBranch { pub: - exprs []Expr // left side - stmts []Stmt // right side - pos token.Position - comment Comment // comment above `xxx {` - is_else bool + exprs []Expr // left side + stmts []Stmt // right side + pos token.Position + comment Comment // comment above `xxx {` + is_else bool post_comments []Comment } @@ -486,6 +486,15 @@ pub mut: else_stmts []Stmt } +pub struct CompFor { +pub: + val_var string + stmts []Stmt +pub mut: + // expr Expr + typ table.Type +} + pub struct ForStmt { pub: cond Expr @@ -594,12 +603,12 @@ pub: pub struct EnumDecl { pub: - name string - is_pub bool - is_flag bool // true when the enum has [flag] tag + name string + is_pub bool + is_flag bool // true when the enum has [flag] tag comments []Comment // enum Abc { /* comments */ ... } - fields []EnumField - pos token.Position + fields []EnumField + pos token.Position } pub struct AliasTypeDecl { @@ -799,6 +808,7 @@ pub: left Expr is_vweb bool vweb_tmpl File + args_var string pub mut: sym table.TypeSymbol } @@ -876,7 +886,7 @@ pub fn (expr Expr) position() token.Position { AsCast { return expr.pos } - // ast.Ident { } + // ast.Ident { } CastExpr { return expr.pos } @@ -904,7 +914,7 @@ pub fn (expr Expr) position() token.Position { IfExpr { return expr.pos } - // ast.IfGuardExpr { } + // ast.IfGuardExpr { } IndexExpr { return expr.pos } @@ -935,12 +945,11 @@ pub fn (expr Expr) position() token.Position { PostfixExpr { return expr.pos } - // ast.None { } + // ast.None { } PrefixExpr { - return expr.pos } - // ast.ParExpr { } + // ast.ParExpr { } SelectorExpr { return expr.pos } @@ -953,14 +962,14 @@ pub fn (expr Expr) position() token.Position { StringInterLiteral { return expr.pos } - // ast.Type { } + // ast.Type { } StructInit { return expr.pos } Likely { return expr.pos } - // ast.TypeOf { } + // ast.TypeOf { } else { return token.Position{} } @@ -971,29 +980,29 @@ pub fn (stmt Stmt) position() token.Position { match stmt { AssertStmt { return stmt.pos } AssignStmt { return stmt.pos } - /* - // Attr { + /* + // Attr { // } // Block { // } // BranchStmt { // } - */ + */ Comment { return stmt.pos } CompIf { return stmt.pos } ConstDecl { return stmt.pos } - /* - // DeferStmt { + /* + // DeferStmt { // } - */ + */ EnumDecl { return stmt.pos } ExprStmt { return stmt.pos } FnDecl { return stmt.pos } ForCStmt { return stmt.pos } ForInStmt { return stmt.pos } ForStmt { return stmt.pos } - /* - // GlobalDecl { + /* + // GlobalDecl { // } // GoStmt { // } @@ -1003,23 +1012,23 @@ pub fn (stmt Stmt) position() token.Position { // } // HashStmt { // } - */ + */ Import { return stmt.pos } - /* - // InterfaceDecl { + /* + // InterfaceDecl { // } // Module { // } - */ + */ Return { return stmt.pos } StructDecl { return stmt.pos } - /* - // TypeDecl { + /* + // TypeDecl { // } // UnsafeStmt { // } - */ - // + */ + // else { return token.Position{} } } } diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 692469b125..fa09860eb5 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -105,9 +105,8 @@ pub fn (mut c Checker) check2(ast_file ast.File) []errors.Error { pub fn (mut c Checker) check_files(ast_files []ast.File) { mut has_main_mod_file := false mut has_main_fn := false - mut files_from_main_module := []&ast.File{} - for i in 0..ast_files.len { + for i in 0 .. ast_files.len { file := &ast_files[i] c.check(file) if file.mod.name == 'main' { @@ -118,7 +117,6 @@ pub fn (mut c Checker) check_files(ast_files []ast.File) { } } } - if has_main_mod_file && !has_main_fn && files_from_main_module.len > 0 { if c.pref.is_script && !c.pref.is_test { first_main_file := files_from_main_module[0] @@ -131,7 +129,6 @@ pub fn (mut c Checker) check_files(ast_files []ast.File) { has_main_fn = true } } - // Make sure fn main is defined in non lib builds if c.pref.build_mode == .build_module || c.pref.is_test { return @@ -163,14 +160,14 @@ fn (mut c Checker) check_file_in_main(file ast.File) bool { c.warn('const $no_pub_in_main_warning', stmt.pos) } } - /* - // TODO not a Stmt + /* + // TODO not a Stmt ast.ConstField { if stmt.is_pub { c.warn('const field `$stmt.name` $no_pub_in_main_warning', stmt.pos) } } - */ + */ ast.EnumDecl { if stmt.is_pub { c.warn('enum `$stmt.name` $no_pub_in_main_warning', stmt.pos) @@ -232,7 +229,7 @@ fn (mut c Checker) check_file_in_main(file ast.File) bool { } fn (mut c Checker) check_valid_snake_case(name, identifier string, pos token.Position) { - if !c.pref.is_vweb && ( name[0] == `_` || name.contains('._') ) { + if !c.pref.is_vweb && (name[0] == `_` || name.contains('._')) { c.error('$identifier `$name` cannot start with `_`', pos) } if util.contains_capital(name) { @@ -378,7 +375,7 @@ pub fn (mut c Checker) struct_init(mut struct_init ast.StructInit) table.Type { .placeholder { c.error('unknown struct: $type_sym.name', struct_init.pos) } - // string & array are also structs but .kind of string/array + // string & array are also structs but .kind of string/array .struct_, .string, .array, .alias { mut info := table.Struct{} if type_sym.kind == .alias { @@ -1044,10 +1041,10 @@ pub fn (mut c Checker) call_fn(mut call_expr ast.CallExpr) table.Type { if rts_info.generic_types.len > 0 { // TODO: multiple generic types // for gt in rts_info.generic_types { - // gtss := c.table.get_type_symbol(gt) + // gtss := c.table.get_type_symbol(gt) // } gts := c.table.get_type_symbol(call_expr.generic_type) - nrt := '${rts.name}<$gts.name>' + nrt := '$rts.name<$gts.name>' idx := c.table.type_idxs[nrt] if idx == 0 { c.error('unknown type: $nrt', call_expr.pos) @@ -1055,8 +1052,7 @@ pub fn (mut c Checker) call_fn(mut call_expr ast.CallExpr) table.Type { call_expr.return_type = table.new_type(idx).derive(f.return_type) } } - } - else { + } else { call_expr.return_type = f.return_type } if f.return_type == table.void_type && @@ -1509,8 +1505,7 @@ pub fn (mut c Checker) assign_stmt(mut assign_stmt ast.AssignStmt) { right_sym := c.table.get_type_symbol(right_type_unwrapped) if (left_type.is_ptr() || left_sym.is_pointer()) && assign_stmt.op !in [.assign, .decl_assign] && !c.inside_unsafe { - c.error('pointer arithmetic is only allowed in `unsafe` blocks', - assign_stmt.pos) + c.error('pointer arithmetic is only allowed in `unsafe` blocks', assign_stmt.pos) } // Single side check match assign_stmt.op { @@ -1732,7 +1727,7 @@ fn (mut c Checker) stmt(node ast.Stmt) { node.pos) } } - // ast.Attr {} + // ast.Attr {} ast.AssignStmt { c.assign_stmt(mut node) } @@ -1744,6 +1739,10 @@ fn (mut c Checker) stmt(node ast.Stmt) { c.error('$node.tok.lit statement not within a loop', node.tok.position()) } } + ast.CompFor { + // node.typ = c.expr(node.expr) + c.stmts(node.stmts) + } ast.CompIf { // c.expr(it.cond) c.stmts(node.stmts) @@ -1897,7 +1896,7 @@ fn (mut c Checker) stmt(node ast.Stmt) { } } } - // ast.HashStmt {} + // ast.HashStmt {} ast.Import {} ast.InterfaceDecl { c.interface_decl(it) @@ -2317,7 +2316,7 @@ pub fn (mut c Checker) ident(mut ident ast.Ident) table.Type { // main.compare_f32 may actually be builtin.compare_f32 saved_mod := ident.mod ident.mod = 'builtin' - builtin_type := c.ident( ident ) + builtin_type := c.ident(ident) if builtin_type != table.void_type { return builtin_type } @@ -2446,7 +2445,7 @@ fn (mut c Checker) match_exprs(mut node ast.MatchExpr, type_sym table.TypeSymbol unhandled << '`$v_str`' } } } - // + // table.Enum { for v in it.vals { if v !in branch_exprs { is_exhaustive = false @@ -2580,8 +2579,7 @@ pub fn (mut c Checker) postfix_expr(node ast.PostfixExpr) table.Type { c.fail_if_immutable(node.expr) } if (typ.is_ptr() || typ_sym.is_pointer()) && !c.inside_unsafe { - c.error('pointer arithmetic is only allowed in `unsafe` blocks', - node.pos) + c.error('pointer arithmetic is only allowed in `unsafe` blocks', node.pos) } return typ } diff --git a/vlib/v/fmt/fmt.v b/vlib/v/fmt/fmt.v index ffc658c906..55af316439 100644 --- a/vlib/v/fmt/fmt.v +++ b/vlib/v/fmt/fmt.v @@ -290,6 +290,7 @@ pub fn (mut f Fmt) stmt(node ast.Stmt) { ast.Comment { f.comment(it) } + ast.CompFor {} ast.CompIf { inversion := if it.is_not { '!' } else { '' } is_opt := if it.is_opt { ' ?' } else { '' } diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index 84e77cf970..7a1eceebe9 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -94,6 +94,7 @@ mut: inside_call bool has_main bool inside_const bool + comp_for_method string // $for method in T { } const ( @@ -625,6 +626,9 @@ fn (mut g Gen) stmt(node ast.Stmt) { // } } ast.Comment {} + ast.CompFor { + g.comp_for(node) + } ast.CompIf { g.comp_if(node) } @@ -1160,7 +1164,7 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) { is_call = true return_type = val.return_type } - // TODO: no buffer fiddling + // TODO: no buffer fiddling ast.AnonFn { if blank_assign { g.write('{') @@ -3044,7 +3048,7 @@ fn (g Gen) sort_structs(typesa []table.TypeSymbol) []table.TypeSymbol { field_deps << dep } } - // table.Interface {} + // table.Interface {} else {} } // add type and dependant types to graph @@ -3504,11 +3508,11 @@ fn (mut g Gen) comp_if_to_ifdef(name string, is_comptime_optional bool) string { 'linux_or_macos' { return '' } - // + // 'js' { return '_VJS' } - // compilers: + // compilers: 'tinyc' { return '__TINYC__' } @@ -3524,7 +3528,7 @@ fn (mut g Gen) comp_if_to_ifdef(name string, is_comptime_optional bool) string { 'cplusplus' { return '__cplusplus' } - // other: + // other: 'debug' { return '_VDEBUG' } diff --git a/vlib/v/gen/comptime.v b/vlib/v/gen/comptime.v index 30173399e7..8671c63abd 100644 --- a/vlib/v/gen/comptime.v +++ b/vlib/v/gen/comptime.v @@ -27,11 +27,40 @@ fn (g &Gen) comptime_call(node ast.ComptimeCall) { g.writeln('// $' + 'method call. sym="$node.sym.name"') mut j := 0 result_type := g.table.find_type_idx('vweb.Result') // TODO not just vweb + if node.method_name == 'method' { + // `app.$method()` + m := node.sym.find_method(g.comp_for_method) or { + return + } + /* + vals := m.attrs[0].split('/') + args := vals.filter(it.starts_with(':')).map(it[1..]) + println(vals) + for val in vals { + } + */ + g.write('${util.no_dots(node.sym.name)}_${g.comp_for_method}(') + g.expr(node.left) + if m.args.len > 1 { + g.write(', ') + } + for i in 0 .. m.args.len - 1 { + g.write('((string*)${node.args_var}.data) [$i] ') + if i < m.args.len - 2 { + g.write(', ') + } + } + g.write(' ); // vweb action call with args') + return + } for method in node.sym.methods { // if method.return_type != table.void_type { if method.return_type != result_type { continue } + if method.args.len != 1 { + continue + } // receiver := method.args[0] // if !p.expr_var.ptr { // p.error('`$p.expr_var.name` needs to be a reference') @@ -69,3 +98,29 @@ fn (mut g Gen) comp_if(it ast.CompIf) { } g.writeln('\n#endif\n// } $it.val\n') } + +fn (mut g Gen) comp_for(node ast.CompFor) { + g.writeln('// comptime $' + 'for {') + sym := g.table.get_type_symbol(g.unwrap_generic(node.typ)) + mut i := 0 + // g.writeln('string method = tos_lit("");') + for method in sym.methods { + if method.attrs.len == 0 { + continue + } + g.comp_for_method = method.name + g.writeln('\t// method $i') + if i == 0 { + g.write('\tstring ') + } + g.writeln('method = tos_lit("$method.name");') + if i == 0 { + g.write('\tstring ') + } + g.writeln('attrs = tos_lit("${method.attrs[0]}");') + g.stmts(node.stmts) + i++ + g.writeln('') + } + g.writeln('// } comptime for') +} diff --git a/vlib/v/gen/js/js.v b/vlib/v/gen/js/js.v index 16910dc379..b3903ff89d 100644 --- a/vlib/v/gen/js/js.v +++ b/vlib/v/gen/js/js.v @@ -422,6 +422,8 @@ fn (mut g JsGen) stmt(node ast.Stmt) { ast.Comment { // Skip: don't generate comments } + ast.CompFor { + } ast.CompIf { // skip: JS has no compile time if } diff --git a/vlib/v/parser/comptime.v b/vlib/v/parser/comptime.v index 35f40127d2..c9a46c2d3d 100644 --- a/vlib/v/parser/comptime.v +++ b/vlib/v/parser/comptime.v @@ -116,12 +116,15 @@ fn (mut p Parser) vweb() ast.ComptimeCall { println('>>> end of vweb template END') println('\n\n') } - file = {file| path:html_name} + file = { + file | + path: html_name + } // copy vars from current fn scope into vweb_tmpl scope for stmt in file.stmts { if stmt is ast.FnDecl { fn_decl := stmt as ast.FnDecl - if fn_decl.name == 'main.vweb_tmpl_${p.cur_fn_name}' { + if fn_decl.name == 'main.vweb_tmpl_$p.cur_fn_name' { tmpl_scope := file.scope.innermost(fn_decl.body_pos.pos) for _, obj in p.scope.objects { if obj is ast.Var { @@ -143,6 +146,32 @@ fn (mut p Parser) vweb() ast.ComptimeCall { } } +fn (mut p Parser) comp_for() ast.CompFor { + println('COMP FOR') + p.next() + p.check(.key_for) + val_var := p.check_name() + p.scope.register(val_var, ast.Var{ + name: val_var + typ: table.string_type + }) + p.scope.register('attrs', ast.Var{ + name: 'attrs' + typ: table.string_type + }) + p.check(.key_in) + // expr := p.expr(0) + typ := p.parse_type() + // p.check(.dot) + // p.check_name() + stmts := p.parse_block() + return ast.CompFor{ + val_var: val_var + stmts: stmts + typ: typ + } +} + fn (mut p Parser) comp_if() ast.Stmt { pos := p.tok.position() p.next() @@ -159,15 +188,13 @@ fn (mut p Parser) comp_if() ast.Stmt { mut skip := false if val in supported_platforms { os := os_from_string(val) - if (!is_not && os != p.pref.os) || - (is_not && os == p.pref.os) { + if (!is_not && os != p.pref.os) || (is_not && os == p.pref.os) { skip = true } } else if val in supported_ccompilers { cc := cc_from_string(val) user_cc := cc_from_string(p.pref.ccompiler) - if (!is_not && cc != user_cc) || - (is_not && cc == user_cc) { + if (!is_not && cc != user_cc) || (is_not && cc == user_cc) { skip = true } } @@ -215,8 +242,7 @@ fn (mut p Parser) comp_if() ast.Stmt { val: val stmts: stmts } - if p.tok.kind == .dollar && - p.peek_tok.kind == .key_else { + if p.tok.kind == .dollar && p.peek_tok.kind == .key_else { p.next() p.next() node.has_else = true @@ -339,6 +365,11 @@ fn (mut p Parser) comptime_method_call(left ast.Expr) ast.ComptimeCall { } */ p.check(.lpar) + mut args_var := '' + if p.tok.kind == .name { + args_var = p.tok.lit + p.next() + } p.check(.rpar) if p.tok.kind == .key_orelse { p.check(.key_orelse) @@ -349,5 +380,6 @@ fn (mut p Parser) comptime_method_call(left ast.Expr) ast.ComptimeCall { return ast.ComptimeCall{ left: left method_name: method_name + args_var: args_var } } diff --git a/vlib/v/parser/fn.v b/vlib/v/parser/fn.v index 136e34db6e..e938b169da 100644 --- a/vlib/v/parser/fn.v +++ b/vlib/v/parser/fn.v @@ -240,6 +240,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl { is_deprecated: is_deprecated ctdefine: ctdefine mod: p.mod + attrs: p.attrs }) } else { if language == .c { diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index cf64b3cc0c..451fd1ca6f 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -536,6 +536,8 @@ pub fn (mut p Parser) stmt(is_top_level bool) ast.Stmt { .dollar { if p.peek_tok.kind == .key_if { return p.comp_if() + } else if p.peek_tok.kind == .key_for { + return p.comp_for() } else if p.peek_tok.kind == .name { return ast.ExprStmt{ expr: p.vweb() @@ -592,7 +594,7 @@ pub fn (mut p Parser) stmt(is_top_level bool) ast.Stmt { p.error_with_pos('const can only be defined at the top level (outside of functions)', p.tok.position()) } - // literals, 'if', etc. in here + // literals, 'if', etc. in here else { return p.parse_multi_expr(is_top_level) } @@ -647,15 +649,21 @@ fn (mut p Parser) parse_attr() ast.Attr { p.next() is_if_attr = true } - mut name := p.check_name() - if p.tok.kind == .colon { - name += ':' + mut name := '' + if p.tok.kind == .string { + name = p.tok.lit p.next() - if p.tok.kind == .name { - name += p.check_name() - } else if p.tok.kind == .string { - name += p.tok.lit + } else { + mut name = p.check_name() + if p.tok.kind == .colon { + name += ':' p.next() + if p.tok.kind == .name { + name += p.check_name() + } else if p.tok.kind == .string { + name += p.tok.lit + p.next() + } } } if is_if_attr { @@ -847,11 +855,10 @@ pub fn (mut p Parser) name_expr() ast.Expr { if p.tok.lit in ['r', 'c', 'js'] && p.peek_tok.kind == .string && !p.inside_str_interp { return p.string_expr() } - known_var := p.mark_var_as_used( p.tok.lit ) + known_var := p.mark_var_as_used(p.tok.lit) mut is_mod_cast := false if p.peek_tok.kind == .dot && !known_var && - (language != .v || p.known_import(p.tok.lit) || - p.mod.all_after_last('.') == p.tok.lit) { + (language != .v || p.known_import(p.tok.lit) || p.mod.all_after_last('.') == p.tok.lit) { if language == .c { mod = 'C' } else if language == .js { @@ -874,8 +881,7 @@ pub fn (mut p Parser) name_expr() ast.Expr { // p.warn('name expr $p.tok.lit $p.peek_tok.str()') // fn call or type cast if p.peek_tok.kind == .lpar || - (p.peek_tok.kind == .lt && !lit0_is_capital && p.peek_tok2.kind == .name && - p.peek_tok3.kind == .gt) { + (p.peek_tok.kind == .lt && !lit0_is_capital && p.peek_tok2.kind == .name && p.peek_tok3.kind == .gt) { // foo() or foo() mut name := p.tok.lit if mod.len > 0 { @@ -884,7 +890,8 @@ pub fn (mut p Parser) name_expr() ast.Expr { name_w_mod := p.prepend_mod(name) // type cast. TODO: finish // if name in table.builtin_type_names { - if (!known_var && (name in p.table.type_idxs || name_w_mod in p.table.type_idxs) && + if (!known_var && (name in p.table.type_idxs || + name_w_mod in p.table.type_idxs) && name !in ['C.stat', 'C.sigaction']) || is_mod_cast { // TODO handle C.stat() mut to_typ := p.parse_type() @@ -918,8 +925,9 @@ pub fn (mut p Parser) name_expr() ast.Expr { // println('calling $p.tok.lit') node = p.call_expr(language, mod) } - } else if (p.peek_tok.kind == .lcbr || (p.peek_tok.kind == .lt && lit0_is_capital)) && !p.inside_match && !p.inside_match_case && !p.inside_if && - !p.inside_for { // && (p.tok.lit[0].is_capital() || p.builtin_mod) { + } else if (p.peek_tok.kind == .lcbr || + (p.peek_tok.kind == .lt && lit0_is_capital)) && !p.inside_match && !p.inside_match_case && + !p.inside_if && !p.inside_for { // && (p.tok.lit[0].is_capital() || p.builtin_mod) { return p.struct_init(false) // short_syntax: false } else if p.peek_tok.kind == .dot && (lit0_is_capital && !known_var && language == .v) { // `Color.green` @@ -1523,7 +1531,8 @@ fn (mut p Parser) type_decl() ast.TypeDecl { decl_pos := start_pos.extend(end_pos) name := p.check_name() if name.len == 1 && name[0].is_capital() { - p.error_with_pos('single letter capital names are reserved for generic template types.', decl_pos) + p.error_with_pos('single letter capital names are reserved for generic template types.', + decl_pos) } mut sum_variants := []table.Type{} if p.tok.kind == .assign { diff --git a/vlib/v/table/table.v b/vlib/v/table/table.v index 845be52652..e8d23c125e 100644 --- a/vlib/v/table/table.v +++ b/vlib/v/table/table.v @@ -30,6 +30,7 @@ pub: is_deprecated bool mod string ctdefine string // compile time define. myflag, when [if myflag] tag + attrs []string pub mut: name string } @@ -225,7 +226,9 @@ pub fn (mut t Table) register_builtin_type_symbol(typ TypeSymbol) int { typ | kind: existing_type.kind } - } else { + } + // + else { t.types[existing_idx] = typ } } diff --git a/vlib/v/tests/comptime_for_test.v b/vlib/v/tests/comptime_for_test.v new file mode 100644 index 0000000000..94b8c28bbe --- /dev/null +++ b/vlib/v/tests/comptime_for_test.v @@ -0,0 +1,27 @@ +struct App { +} + +['foo/bar/three'] +fn (mut app App) run() { +} + +['attr2'] +fn (mut app App) method2() { +} + +fn test_comptime_for() { + /* + app := App{} + + $for method in App { //.method_attrs { + words := attrs.split('/') + println(words) + //println(method.value) + } + assert true + println('DONE') + */ + if true {} + // + else{} +} diff --git a/vlib/vweb/vweb.v b/vlib/vweb/vweb.v index e1be618af6..8f708b13f5 100644 --- a/vlib/vweb/vweb.v +++ b/vlib/vweb/vweb.v @@ -255,13 +255,6 @@ fn handle_conn(conn net.Socket, mut app T) { } } - mut action := vals[1][1..].all_before('/') - if action.contains('?') { - action = action.all_before('?') - } - if action == '' { - action = 'index' - } req := http.Request{ headers: http.parse_headers(headers) //s.split_into_lines()) data: strip(body) @@ -274,7 +267,7 @@ fn handle_conn(conn net.Socket, mut app T) { println('req.headers = ') println(req.headers) println('req.data="$req.data"' ) - println('vweb action = "$action"') + //println('vweb action = "$action"') } //mut app := T{ app.vweb = Context{ @@ -316,19 +309,60 @@ fn handle_conn(conn net.Socket, mut app T) { data.free() return } - + app.init() // Call the right action + mut action := '' + mut route_words := []string{} + mut ok := true + url_words := vals[1][1..].split('/') + mut vars := []string{cap: route_words.len} + $for method in T { + ok = true + route_words = attrs[1..].split('/') + //println('words:') println(route_words) + //println('vals:') println(url_words) + vars = []string{cap: route_words.len} + if route_words.len == url_words.len { + // match `/:user/:repo/tree` to `/vlang/v/tree` + for i, word in route_words { + if word.starts_with(':') { + // remember and skip the var + vars << url_words[i] + continue + } + if word != url_words[i] { + ok = false + break + } + } + } + if ok { + action = method + app.$method(vars) + conn.close() or {} + return + } + } + // No route matched, just do a simple `/home` => `action=home` + if action == '' { + action = vals[1][1..].all_before('/') + if action.contains('?') { + action = action.all_before('?') + } + if action == '' { + action = 'index' + } + } $if debug { println('action=$action') } - app.init() + app.$action() /* app.$action() or { conn.send_string(http_404) or {} } */ - conn.close() or {} //app.reset() return