vweb: ['/:arg1/:arg2/action'] attribute
parent
f03688e443
commit
b7175b54eb
|
@ -249,3 +249,9 @@ fn __print_assert_failure(i &VAssertMetaInfo) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct MethodAttr {
|
||||||
|
pub:
|
||||||
|
value string
|
||||||
|
method string
|
||||||
|
}
|
||||||
|
|
|
@ -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{} }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 { '' }
|
||||||
|
|
|
@ -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'
|
||||||
}
|
}
|
||||||
|
|
|
@ -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')
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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{}
|
||||||
|
}
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue