vweb: ['/:arg1/:arg2/action'] attribute

pull/5638/head
Alexander Medvednikov 2020-07-03 15:10:39 +02:00
parent f03688e443
commit b7175b54eb
13 changed files with 281 additions and 100 deletions

View File

@ -249,3 +249,9 @@ fn __print_assert_failure(i &VAssertMetaInfo) {
} }
} }
} }
pub struct MethodAttr {
pub:
value string
method string
}

View File

@ -15,10 +15,10 @@ pub type Expr = AnonFn | ArrayInit | AsCast | Assoc | BoolLiteral | CallExpr | C
ParExpr | PostfixExpr | PrefixExpr | RangeExpr | SelectorExpr | SizeOf | SqlExpr | StringInterLiteral | ParExpr | PostfixExpr | PrefixExpr | RangeExpr | SelectorExpr | SizeOf | SqlExpr | StringInterLiteral |
StringLiteral | StructInit | Type | TypeOf StringLiteral | StructInit | Type | TypeOf
pub type Stmt = AssertStmt | AssignStmt | Attr | Block | BranchStmt | Comment | CompIf | pub type Stmt = AssertStmt | AssignStmt | Attr | Block | BranchStmt | Comment | CompFor |
ConstDecl | DeferStmt | EnumDecl | ExprStmt | FnDecl | ForCStmt | ForInStmt | ForStmt | CompIf | ConstDecl | DeferStmt | EnumDecl | ExprStmt | FnDecl | ForCStmt | ForInStmt |
GlobalDecl | GoStmt | GotoLabel | GotoStmt | HashStmt | Import | InterfaceDecl | Module | ForStmt | GlobalDecl | GoStmt | GotoLabel | GotoStmt | HashStmt | Import | InterfaceDecl |
Return | SqlStmt | StructDecl | TypeDecl | UnsafeStmt Module | Return | SqlStmt | StructDecl | TypeDecl | UnsafeStmt
pub type ScopeObject = ConstField | GlobalDecl | Var pub type ScopeObject = ConstField | GlobalDecl | Var
@ -457,11 +457,11 @@ pub mut:
pub struct MatchBranch { pub struct MatchBranch {
pub: pub:
exprs []Expr // left side exprs []Expr // left side
stmts []Stmt // right side stmts []Stmt // right side
pos token.Position pos token.Position
comment Comment // comment above `xxx {` comment Comment // comment above `xxx {`
is_else bool is_else bool
post_comments []Comment post_comments []Comment
} }
@ -486,6 +486,15 @@ pub mut:
else_stmts []Stmt else_stmts []Stmt
} }
pub struct CompFor {
pub:
val_var string
stmts []Stmt
pub mut:
// expr Expr
typ table.Type
}
pub struct ForStmt { pub struct ForStmt {
pub: pub:
cond Expr cond Expr
@ -594,12 +603,12 @@ pub:
pub struct EnumDecl { pub struct EnumDecl {
pub: pub:
name string name string
is_pub bool is_pub bool
is_flag bool // true when the enum has [flag] tag is_flag bool // true when the enum has [flag] tag
comments []Comment // enum Abc { /* comments */ ... } comments []Comment // enum Abc { /* comments */ ... }
fields []EnumField fields []EnumField
pos token.Position pos token.Position
} }
pub struct AliasTypeDecl { pub struct AliasTypeDecl {
@ -799,6 +808,7 @@ pub:
left Expr left Expr
is_vweb bool is_vweb bool
vweb_tmpl File vweb_tmpl File
args_var string
pub mut: pub mut:
sym table.TypeSymbol sym table.TypeSymbol
} }
@ -876,7 +886,7 @@ pub fn (expr Expr) position() token.Position {
AsCast { AsCast {
return expr.pos return expr.pos
} }
// ast.Ident { } // ast.Ident { }
CastExpr { CastExpr {
return expr.pos return expr.pos
} }
@ -904,7 +914,7 @@ pub fn (expr Expr) position() token.Position {
IfExpr { IfExpr {
return expr.pos return expr.pos
} }
// ast.IfGuardExpr { } // ast.IfGuardExpr { }
IndexExpr { IndexExpr {
return expr.pos return expr.pos
} }
@ -935,12 +945,11 @@ pub fn (expr Expr) position() token.Position {
PostfixExpr { PostfixExpr {
return expr.pos return expr.pos
} }
// ast.None { } // ast.None { }
PrefixExpr { PrefixExpr {
return expr.pos return expr.pos
} }
// ast.ParExpr { } // ast.ParExpr { }
SelectorExpr { SelectorExpr {
return expr.pos return expr.pos
} }
@ -953,14 +962,14 @@ pub fn (expr Expr) position() token.Position {
StringInterLiteral { StringInterLiteral {
return expr.pos return expr.pos
} }
// ast.Type { } // ast.Type { }
StructInit { StructInit {
return expr.pos return expr.pos
} }
Likely { Likely {
return expr.pos return expr.pos
} }
// ast.TypeOf { } // ast.TypeOf { }
else { else {
return token.Position{} return token.Position{}
} }
@ -971,29 +980,29 @@ pub fn (stmt Stmt) position() token.Position {
match stmt { match stmt {
AssertStmt { return stmt.pos } AssertStmt { return stmt.pos }
AssignStmt { return stmt.pos } AssignStmt { return stmt.pos }
/* /*
// Attr { // Attr {
// } // }
// Block { // Block {
// } // }
// BranchStmt { // BranchStmt {
// } // }
*/ */
Comment { return stmt.pos } Comment { return stmt.pos }
CompIf { return stmt.pos } CompIf { return stmt.pos }
ConstDecl { return stmt.pos } ConstDecl { return stmt.pos }
/* /*
// DeferStmt { // DeferStmt {
// } // }
*/ */
EnumDecl { return stmt.pos } EnumDecl { return stmt.pos }
ExprStmt { return stmt.pos } ExprStmt { return stmt.pos }
FnDecl { return stmt.pos } FnDecl { return stmt.pos }
ForCStmt { return stmt.pos } ForCStmt { return stmt.pos }
ForInStmt { return stmt.pos } ForInStmt { return stmt.pos }
ForStmt { return stmt.pos } ForStmt { return stmt.pos }
/* /*
// GlobalDecl { // GlobalDecl {
// } // }
// GoStmt { // GoStmt {
// } // }
@ -1003,23 +1012,23 @@ pub fn (stmt Stmt) position() token.Position {
// } // }
// HashStmt { // HashStmt {
// } // }
*/ */
Import { return stmt.pos } Import { return stmt.pos }
/* /*
// InterfaceDecl { // InterfaceDecl {
// } // }
// Module { // Module {
// } // }
*/ */
Return { return stmt.pos } Return { return stmt.pos }
StructDecl { return stmt.pos } StructDecl { return stmt.pos }
/* /*
// TypeDecl { // TypeDecl {
// } // }
// UnsafeStmt { // UnsafeStmt {
// } // }
*/ */
// //
else { return token.Position{} } else { return token.Position{} }
} }
} }

View File

@ -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) { pub fn (mut c Checker) check_files(ast_files []ast.File) {
mut has_main_mod_file := false mut has_main_mod_file := false
mut has_main_fn := false mut has_main_fn := false
mut files_from_main_module := []&ast.File{} 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] file := &ast_files[i]
c.check(file) c.check(file)
if file.mod.name == 'main' { 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 has_main_mod_file && !has_main_fn && files_from_main_module.len > 0 {
if c.pref.is_script && !c.pref.is_test { if c.pref.is_script && !c.pref.is_test {
first_main_file := files_from_main_module[0] 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 has_main_fn = true
} }
} }
// Make sure fn main is defined in non lib builds // Make sure fn main is defined in non lib builds
if c.pref.build_mode == .build_module || c.pref.is_test { if c.pref.build_mode == .build_module || c.pref.is_test {
return 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) c.warn('const $no_pub_in_main_warning', stmt.pos)
} }
} }
/* /*
// TODO not a Stmt // TODO not a Stmt
ast.ConstField { ast.ConstField {
if stmt.is_pub { if stmt.is_pub {
c.warn('const field `$stmt.name` $no_pub_in_main_warning', stmt.pos) c.warn('const field `$stmt.name` $no_pub_in_main_warning', stmt.pos)
} }
} }
*/ */
ast.EnumDecl { ast.EnumDecl {
if stmt.is_pub { if stmt.is_pub {
c.warn('enum `$stmt.name` $no_pub_in_main_warning', stmt.pos) 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) { 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) c.error('$identifier `$name` cannot start with `_`', pos)
} }
if util.contains_capital(name) { if util.contains_capital(name) {
@ -378,7 +375,7 @@ pub fn (mut c Checker) struct_init(mut struct_init ast.StructInit) table.Type {
.placeholder { .placeholder {
c.error('unknown struct: $type_sym.name', struct_init.pos) 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 { .struct_, .string, .array, .alias {
mut info := table.Struct{} mut info := table.Struct{}
if type_sym.kind == .alias { 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 { if rts_info.generic_types.len > 0 {
// TODO: multiple generic types // TODO: multiple generic types
// for gt in rts_info.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) 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] idx := c.table.type_idxs[nrt]
if idx == 0 { if idx == 0 {
c.error('unknown type: $nrt', call_expr.pos) 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) call_expr.return_type = table.new_type(idx).derive(f.return_type)
} }
} }
} } else {
else {
call_expr.return_type = f.return_type call_expr.return_type = f.return_type
} }
if f.return_type == table.void_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) right_sym := c.table.get_type_symbol(right_type_unwrapped)
if (left_type.is_ptr() || left_sym.is_pointer()) && if (left_type.is_ptr() || left_sym.is_pointer()) &&
assign_stmt.op !in [.assign, .decl_assign] && !c.inside_unsafe { assign_stmt.op !in [.assign, .decl_assign] && !c.inside_unsafe {
c.error('pointer arithmetic is only allowed in `unsafe` blocks', c.error('pointer arithmetic is only allowed in `unsafe` blocks', assign_stmt.pos)
assign_stmt.pos)
} }
// Single side check // Single side check
match assign_stmt.op { match assign_stmt.op {
@ -1732,7 +1727,7 @@ fn (mut c Checker) stmt(node ast.Stmt) {
node.pos) node.pos)
} }
} }
// ast.Attr {} // ast.Attr {}
ast.AssignStmt { ast.AssignStmt {
c.assign_stmt(mut node) 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()) 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 { ast.CompIf {
// c.expr(it.cond) // c.expr(it.cond)
c.stmts(node.stmts) c.stmts(node.stmts)
@ -1897,7 +1896,7 @@ fn (mut c Checker) stmt(node ast.Stmt) {
} }
} }
} }
// ast.HashStmt {} // ast.HashStmt {}
ast.Import {} ast.Import {}
ast.InterfaceDecl { ast.InterfaceDecl {
c.interface_decl(it) 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 // main.compare_f32 may actually be builtin.compare_f32
saved_mod := ident.mod saved_mod := ident.mod
ident.mod = 'builtin' ident.mod = 'builtin'
builtin_type := c.ident( ident ) builtin_type := c.ident(ident)
if builtin_type != table.void_type { if builtin_type != table.void_type {
return builtin_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`' unhandled << '`$v_str`'
} }
} } } }
// //
table.Enum { for v in it.vals { table.Enum { for v in it.vals {
if v !in branch_exprs { if v !in branch_exprs {
is_exhaustive = false 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) c.fail_if_immutable(node.expr)
} }
if (typ.is_ptr() || typ_sym.is_pointer()) && !c.inside_unsafe { if (typ.is_ptr() || typ_sym.is_pointer()) && !c.inside_unsafe {
c.error('pointer arithmetic is only allowed in `unsafe` blocks', c.error('pointer arithmetic is only allowed in `unsafe` blocks', node.pos)
node.pos)
} }
return typ return typ
} }

View File

@ -290,6 +290,7 @@ pub fn (mut f Fmt) stmt(node ast.Stmt) {
ast.Comment { ast.Comment {
f.comment(it) f.comment(it)
} }
ast.CompFor {}
ast.CompIf { ast.CompIf {
inversion := if it.is_not { '!' } else { '' } inversion := if it.is_not { '!' } else { '' }
is_opt := if it.is_opt { ' ?' } else { '' } is_opt := if it.is_opt { ' ?' } else { '' }

View File

@ -94,6 +94,7 @@ mut:
inside_call bool inside_call bool
has_main bool has_main bool
inside_const bool inside_const bool
comp_for_method string // $for method in T {
} }
const ( const (
@ -625,6 +626,9 @@ fn (mut g Gen) stmt(node ast.Stmt) {
// } // }
} }
ast.Comment {} ast.Comment {}
ast.CompFor {
g.comp_for(node)
}
ast.CompIf { ast.CompIf {
g.comp_if(node) g.comp_if(node)
} }
@ -1160,7 +1164,7 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
is_call = true is_call = true
return_type = val.return_type return_type = val.return_type
} }
// TODO: no buffer fiddling // TODO: no buffer fiddling
ast.AnonFn { ast.AnonFn {
if blank_assign { if blank_assign {
g.write('{') g.write('{')
@ -3044,7 +3048,7 @@ fn (g Gen) sort_structs(typesa []table.TypeSymbol) []table.TypeSymbol {
field_deps << dep field_deps << dep
} }
} }
// table.Interface {} // table.Interface {}
else {} else {}
} }
// add type and dependant types to graph // 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' { 'linux_or_macos' {
return '' return ''
} }
// //
'js' { 'js' {
return '_VJS' return '_VJS'
} }
// compilers: // compilers:
'tinyc' { 'tinyc' {
return '__TINYC__' return '__TINYC__'
} }
@ -3524,7 +3528,7 @@ fn (mut g Gen) comp_if_to_ifdef(name string, is_comptime_optional bool) string {
'cplusplus' { 'cplusplus' {
return '__cplusplus' return '__cplusplus'
} }
// other: // other:
'debug' { 'debug' {
return '_VDEBUG' return '_VDEBUG'
} }

View File

@ -27,11 +27,40 @@ fn (g &Gen) comptime_call(node ast.ComptimeCall) {
g.writeln('// $' + 'method call. sym="$node.sym.name"') g.writeln('// $' + 'method call. sym="$node.sym.name"')
mut j := 0 mut j := 0
result_type := g.table.find_type_idx('vweb.Result') // TODO not just vweb 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 { for method in node.sym.methods {
// if method.return_type != table.void_type { // if method.return_type != table.void_type {
if method.return_type != result_type { if method.return_type != result_type {
continue continue
} }
if method.args.len != 1 {
continue
}
// receiver := method.args[0] // receiver := method.args[0]
// if !p.expr_var.ptr { // if !p.expr_var.ptr {
// p.error('`$p.expr_var.name` needs to be a reference') // 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') 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')
}

View File

@ -422,6 +422,8 @@ fn (mut g JsGen) stmt(node ast.Stmt) {
ast.Comment { ast.Comment {
// Skip: don't generate comments // Skip: don't generate comments
} }
ast.CompFor {
}
ast.CompIf { ast.CompIf {
// skip: JS has no compile time if // skip: JS has no compile time if
} }

View File

@ -116,12 +116,15 @@ fn (mut p Parser) vweb() ast.ComptimeCall {
println('>>> end of vweb template END') println('>>> end of vweb template END')
println('\n\n') println('\n\n')
} }
file = {file| path:html_name} file = {
file |
path: html_name
}
// copy vars from current fn scope into vweb_tmpl scope // copy vars from current fn scope into vweb_tmpl scope
for stmt in file.stmts { for stmt in file.stmts {
if stmt is ast.FnDecl { if stmt is ast.FnDecl {
fn_decl := stmt as 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) tmpl_scope := file.scope.innermost(fn_decl.body_pos.pos)
for _, obj in p.scope.objects { for _, obj in p.scope.objects {
if obj is ast.Var { 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 { fn (mut p Parser) comp_if() ast.Stmt {
pos := p.tok.position() pos := p.tok.position()
p.next() p.next()
@ -159,15 +188,13 @@ fn (mut p Parser) comp_if() ast.Stmt {
mut skip := false mut skip := false
if val in supported_platforms { if val in supported_platforms {
os := os_from_string(val) os := os_from_string(val)
if (!is_not && os != p.pref.os) || if (!is_not && os != p.pref.os) || (is_not && os == p.pref.os) {
(is_not && os == p.pref.os) {
skip = true skip = true
} }
} else if val in supported_ccompilers { } else if val in supported_ccompilers {
cc := cc_from_string(val) cc := cc_from_string(val)
user_cc := cc_from_string(p.pref.ccompiler) user_cc := cc_from_string(p.pref.ccompiler)
if (!is_not && cc != user_cc) || if (!is_not && cc != user_cc) || (is_not && cc == user_cc) {
(is_not && cc == user_cc) {
skip = true skip = true
} }
} }
@ -215,8 +242,7 @@ fn (mut p Parser) comp_if() ast.Stmt {
val: val val: val
stmts: stmts stmts: stmts
} }
if p.tok.kind == .dollar && if p.tok.kind == .dollar && p.peek_tok.kind == .key_else {
p.peek_tok.kind == .key_else {
p.next() p.next()
p.next() p.next()
node.has_else = true node.has_else = true
@ -339,6 +365,11 @@ fn (mut p Parser) comptime_method_call(left ast.Expr) ast.ComptimeCall {
} }
*/ */
p.check(.lpar) p.check(.lpar)
mut args_var := ''
if p.tok.kind == .name {
args_var = p.tok.lit
p.next()
}
p.check(.rpar) p.check(.rpar)
if p.tok.kind == .key_orelse { if p.tok.kind == .key_orelse {
p.check(.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{ return ast.ComptimeCall{
left: left left: left
method_name: method_name method_name: method_name
args_var: args_var
} }
} }

View File

@ -240,6 +240,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
is_deprecated: is_deprecated is_deprecated: is_deprecated
ctdefine: ctdefine ctdefine: ctdefine
mod: p.mod mod: p.mod
attrs: p.attrs
}) })
} else { } else {
if language == .c { if language == .c {

View File

@ -536,6 +536,8 @@ pub fn (mut p Parser) stmt(is_top_level bool) ast.Stmt {
.dollar { .dollar {
if p.peek_tok.kind == .key_if { if p.peek_tok.kind == .key_if {
return p.comp_if() return p.comp_if()
} else if p.peek_tok.kind == .key_for {
return p.comp_for()
} else if p.peek_tok.kind == .name { } else if p.peek_tok.kind == .name {
return ast.ExprStmt{ return ast.ExprStmt{
expr: p.vweb() 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.error_with_pos('const can only be defined at the top level (outside of functions)',
p.tok.position()) p.tok.position())
} }
// literals, 'if', etc. in here // literals, 'if', etc. in here
else { else {
return p.parse_multi_expr(is_top_level) return p.parse_multi_expr(is_top_level)
} }
@ -647,15 +649,21 @@ fn (mut p Parser) parse_attr() ast.Attr {
p.next() p.next()
is_if_attr = true is_if_attr = true
} }
mut name := p.check_name() mut name := ''
if p.tok.kind == .colon { if p.tok.kind == .string {
name += ':' name = p.tok.lit
p.next() p.next()
if p.tok.kind == .name { } else {
name += p.check_name() mut name = p.check_name()
} else if p.tok.kind == .string { if p.tok.kind == .colon {
name += p.tok.lit name += ':'
p.next() 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 { 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 { if p.tok.lit in ['r', 'c', 'js'] && p.peek_tok.kind == .string && !p.inside_str_interp {
return p.string_expr() 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 mut is_mod_cast := false
if p.peek_tok.kind == .dot && !known_var && if p.peek_tok.kind == .dot && !known_var &&
(language != .v || p.known_import(p.tok.lit) || (language != .v || p.known_import(p.tok.lit) || p.mod.all_after_last('.') == p.tok.lit) {
p.mod.all_after_last('.') == p.tok.lit) {
if language == .c { if language == .c {
mod = 'C' mod = 'C'
} else if language == .js { } 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()') // p.warn('name expr $p.tok.lit $p.peek_tok.str()')
// fn call or type cast // fn call or type cast
if p.peek_tok.kind == .lpar || if p.peek_tok.kind == .lpar ||
(p.peek_tok.kind == .lt && !lit0_is_capital && p.peek_tok2.kind == .name && (p.peek_tok.kind == .lt && !lit0_is_capital && p.peek_tok2.kind == .name && p.peek_tok3.kind == .gt) {
p.peek_tok3.kind == .gt) {
// foo() or foo<int>() // foo() or foo<int>()
mut name := p.tok.lit mut name := p.tok.lit
if mod.len > 0 { if mod.len > 0 {
@ -884,7 +890,8 @@ pub fn (mut p Parser) name_expr() ast.Expr {
name_w_mod := p.prepend_mod(name) name_w_mod := p.prepend_mod(name)
// type cast. TODO: finish // type cast. TODO: finish
// if name in table.builtin_type_names { // 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 { name !in ['C.stat', 'C.sigaction']) || is_mod_cast {
// TODO handle C.stat() // TODO handle C.stat()
mut to_typ := p.parse_type() mut to_typ := p.parse_type()
@ -918,8 +925,9 @@ pub fn (mut p Parser) name_expr() ast.Expr {
// println('calling $p.tok.lit') // println('calling $p.tok.lit')
node = p.call_expr(language, mod) 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 && } else if (p.peek_tok.kind == .lcbr ||
!p.inside_for { // && (p.tok.lit[0].is_capital() || p.builtin_mod) { (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 return p.struct_init(false) // short_syntax: false
} else if p.peek_tok.kind == .dot && (lit0_is_capital && !known_var && language == .v) { } else if p.peek_tok.kind == .dot && (lit0_is_capital && !known_var && language == .v) {
// `Color.green` // `Color.green`
@ -1523,7 +1531,8 @@ fn (mut p Parser) type_decl() ast.TypeDecl {
decl_pos := start_pos.extend(end_pos) decl_pos := start_pos.extend(end_pos)
name := p.check_name() name := p.check_name()
if name.len == 1 && name[0].is_capital() { 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{} mut sum_variants := []table.Type{}
if p.tok.kind == .assign { if p.tok.kind == .assign {

View File

@ -30,6 +30,7 @@ pub:
is_deprecated bool is_deprecated bool
mod string mod string
ctdefine string // compile time define. myflag, when [if myflag] tag ctdefine string // compile time define. myflag, when [if myflag] tag
attrs []string
pub mut: pub mut:
name string name string
} }
@ -225,7 +226,9 @@ pub fn (mut t Table) register_builtin_type_symbol(typ TypeSymbol) int {
typ | typ |
kind: existing_type.kind kind: existing_type.kind
} }
} else { }
//
else {
t.types[existing_idx] = typ t.types[existing_idx] = typ
} }
} }

View File

@ -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{}
}

View File

@ -255,13 +255,6 @@ fn handle_conn<T>(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{ req := http.Request{
headers: http.parse_headers(headers) //s.split_into_lines()) headers: http.parse_headers(headers) //s.split_into_lines())
data: strip(body) data: strip(body)
@ -274,7 +267,7 @@ fn handle_conn<T>(conn net.Socket, mut app T) {
println('req.headers = ') println('req.headers = ')
println(req.headers) println(req.headers)
println('req.data="$req.data"' ) println('req.data="$req.data"' )
println('vweb action = "$action"') //println('vweb action = "$action"')
} }
//mut app := T{ //mut app := T{
app.vweb = Context{ app.vweb = Context{
@ -316,19 +309,60 @@ fn handle_conn<T>(conn net.Socket, mut app T) {
data.free() data.free()
return return
} }
app.init()
// Call the right action // 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 { $if debug {
println('action=$action') println('action=$action')
} }
app.init()
app.$action() app.$action()
/* /*
app.$action() or { app.$action() or {
conn.send_string(http_404) or {} conn.send_string(http_404) or {}
} }
*/ */
conn.close() or {} conn.close() or {}
//app.reset() //app.reset()
return return