From 892d1c6aab169fa0109c825ffea9ebebb4afc583 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Thu, 24 Oct 2019 19:44:49 +0300 Subject: [PATCH] vweb: first step to revive it --- examples/vweb/{test_app.v => test_vweb_app.v} | 6 +- vlib/compiler/fn.v | 10 +- vlib/compiler/parser.v | 30 ++--- vlib/compiler/struct.v | 1 + vlib/http/http.v | 70 +++++------ vlib/net/socket.v | 2 +- vlib/vweb/vweb.v | 111 +++++++++--------- 7 files changed, 116 insertions(+), 114 deletions(-) rename examples/vweb/{test_app.v => test_vweb_app.v} (88%) diff --git a/examples/vweb/test_app.v b/examples/vweb/test_vweb_app.v similarity index 88% rename from examples/vweb/test_app.v rename to examples/vweb/test_vweb_app.v index 380e56f59a..eedcbcc9b0 100644 --- a/examples/vweb/test_app.v +++ b/examples/vweb/test_vweb_app.v @@ -3,7 +3,7 @@ module main import vweb const ( - Port = 8082 + port = 8082 ) struct App { @@ -13,7 +13,9 @@ pub mut: } fn main() { - vweb.run(Port) + mut app := App{} + vweb.run(app, port) + //vweb.run(Port) } pub fn (app mut App) init() { diff --git a/vlib/compiler/fn.v b/vlib/compiler/fn.v index e968c4ba56..175e182aa6 100644 --- a/vlib/compiler/fn.v +++ b/vlib/compiler/fn.v @@ -275,8 +275,8 @@ fn (p mut Parser) fn_decl() { // C function header def? (fn C.NSMakeRect(int,int,int,int)) is_c := f.name == 'C' && p.tok == .dot // Just fn signature? only builtin.v + default build mode - if p.pref.build_mode == .build_module { - //println('\n\nfn_decl() name=$f.name receiver_typ=$receiver_typ nogen=$p.cgen.nogen') + if p.pref.is_verbose { // p.pref.build_mode == .build_module { + println('\n\nfn_decl() name=$f.name receiver_typ=$receiver_typ nogen=$p.cgen.nogen') } if is_c { p.check(.dot) @@ -561,8 +561,10 @@ fn (p mut Parser) check_unused_variables() { if !var.is_used && !p.pref.is_repl && !var.is_arg && !p.pref.translated { p.production_error_with_token_index('`$var.name` declared and not used', var.token_idx ) } - if !var.is_changed && var.is_mut && !p.pref.is_repl && !p.pref.translated { - p.error_with_token_index( '`$var.name` is declared as mutable, but it was never changed', var.token_idx ) + if !var.is_changed && var.is_mut && !p.pref.is_repl && + !p.pref.translated && var.typ != 'T*' + { + p.error_with_token_index('`$var.name` is declared as mutable, but it was never changed', var.token_idx ) } } } diff --git a/vlib/compiler/parser.v b/vlib/compiler/parser.v index 41e5e52afd..bc69c98bde 100644 --- a/vlib/compiler/parser.v +++ b/vlib/compiler/parser.v @@ -472,7 +472,7 @@ fn (p mut Parser) import_statement() { if p.tok != .name { p.error('bad import format') } - if p.peek() == .number { // && p.scanner.text[p.scanner.pos + 1] == `.` { + if p.peek() == .number { p.error('bad import format. module/submodule names cannot begin with a number') } import_tok_idx := p.token_idx-1 @@ -513,14 +513,6 @@ fn (p mut Parser) const_decl() { if is_pub { p.next() } - if p.tok == .key_import { - p.error_with_token_index( - '`import const` was removed from the language, ' + - 'because predeclaring C constants is not needed anymore. ' + - 'You can use them directly with C.CONST_NAME', - p.cur_tok_index() - ) - } p.inside_const = true p.check(.key_const) p.fspace() @@ -659,13 +651,13 @@ fn (p mut Parser) interface_method(field_name, receiver string) &Fn { fn key_to_type_cat(tok TokenKind) TypeCategory { match tok { - .key_interface { return TypeCategory.interface_ } - .key_struct { return TypeCategory.struct_ } - .key_union { return TypeCategory.union_ } - //TokenKind.key_ => return .interface_ + .key_interface { return .interface_ } + .key_struct { return .struct_ } + .key_union { return .union_ } + //TokenKind.key_ => return .interface_ } verror('Unknown token: $tok') - return TypeCategory.builtin + return .builtin } // check_name checks for a name token and returns its literal @@ -727,10 +719,10 @@ fn (p mut Parser) check(expected TokenKind) { */ p.next() -if p.scanner.line_comment != '' { - //p.fgenln('// ! "$p.scanner.line_comment"') - //p.scanner.line_comment = '' -} + //if p.scanner.line_comment != '' { + //p.fgenln('// ! "$p.scanner.line_comment"') + //p.scanner.line_comment = '' + //} } @@ -894,7 +886,7 @@ fn (p mut Parser) get_type() string { p.error('unknown type `$typ`') } } - else if !t.is_public && t.mod != p.mod && t.name != '' { + else if !t.is_public && t.mod != p.mod && t.name != '' && !p.first_pass() { p.error('type `$t.name` is private') } } diff --git a/vlib/compiler/struct.v b/vlib/compiler/struct.v index 1e32bdee87..4a669e8633 100644 --- a/vlib/compiler/struct.v +++ b/vlib/compiler/struct.v @@ -81,6 +81,7 @@ fn (p mut Parser) struct_decl() { typ.is_placeholder = false typ.cat = cat typ.parent = objc_parent + typ.is_public = is_pub p.table.rewrite_type(typ) } else { diff --git a/vlib/http/http.v b/vlib/http/http.v index 9271c98870..ef43e46109 100644 --- a/vlib/http/http.v +++ b/vlib/http/http.v @@ -11,9 +11,9 @@ const ( max_redirects = 4 ) -struct Request { +pub struct Request { pub: - headers map[string]string + headers map[string]string method string // cookies map[string]string h string @@ -27,10 +27,10 @@ pub: user_agent string } -struct Response { +pub struct Response { pub: text string - headers map[string]string + headers map[string]string status_code int } @@ -56,7 +56,7 @@ pub fn post(url, data string) ?Response { pub fn new_request(typ, _url, _data string) ?Request { if _url == '' { - return error('bad url') + return error('bad url') } mut url := _url mut data := _data @@ -77,9 +77,9 @@ pub fn new_request(typ, _url, _data string) ?Request { } pub fn get_text(url string) string { - resp := get(url) or { return '' } - return resp.text -} + resp := get(url) or { return '' } + return resp.text +} fn (req mut Request) free() { req.headers.free() @@ -172,29 +172,29 @@ fn (req &Request) method_and_url_to_response(method string, url net_dot_urllib.U fn parse_response(resp string) Response { mut headers := map[string]string - first_header := resp.all_before('\n') - mut status_code := 0 + first_header := resp.all_before('\n') + mut status_code := 0 if first_header.contains('HTTP/') { val := first_header.find_between(' ', ' ') status_code = val.int() } - mut text := '' - // Build resp headers map and separate the body - mut nl_pos := 3 - mut i := 1 - for { - old_pos := nl_pos - nl_pos = resp.index_after('\n', nl_pos+1) + mut text := '' + // Build resp headers map and separate the body + mut nl_pos := 3 + mut i := 1 + for { + old_pos := nl_pos + nl_pos = resp.index_after('\n', nl_pos+1) if nl_pos == -1 { - break - } - h := resp.substr(old_pos + 1, nl_pos) - // End of headers + break + } + h := resp.substr(old_pos + 1, nl_pos) + // End of headers if h.len <= 1 { - text = resp.right(nl_pos + 1) - break - } - i++ + text = resp.right(nl_pos + 1) + break + } + i++ pos := h.index(':') if pos == -1 { continue @@ -212,9 +212,9 @@ fn parse_response(resp string) Response { } return Response { - status_code: status_code + status_code: status_code headers: headers - text: text + text: text } } @@ -222,33 +222,33 @@ fn (req &Request) build_request_headers(method, host_name, path string) string { ua := req.user_agent mut uheaders := []string for key, val in req.headers { - uheaders << '${key}: ${val}\r\n' + uheaders << '${key}: ${val}\r\n' } if req.data.len > 0 { uheaders << 'Content-Length: ${req.data.len}\r\n' } - return '$method $path HTTP/1.1\r\n' + - 'Host: $host_name\r\n' + + return '$method $path HTTP/1.1\r\n' + + 'Host: $host_name\r\n' + 'User-Agent: $ua\r\n' + uheaders.join('') + - 'Connection: close\r\n\r\n' + + 'Connection: close\r\n\r\n' + req.data } pub fn unescape_url(s string) string { - panic('http.unescape_url() was replaced with urllib.query_unescape()') + panic('http.unescape_url() was replaced with urllib.query_unescape()') } pub fn escape_url(s string) string { - panic('http.escape_url() was replaced with urllib.query_escape()') + panic('http.escape_url() was replaced with urllib.query_escape()') } pub fn unescape(s string) string { - panic('http.unescape() was replaced with http.unescape_url()') + panic('http.unescape() was replaced with http.unescape_url()') } pub fn escape(s string) string { - panic('http.escape() was replaced with http.escape_url()') + panic('http.escape() was replaced with http.escape_url()') } type wsfn fn (s string, ptr voidptr) diff --git a/vlib/net/socket.v b/vlib/net/socket.v index d480866af0..016433c184 100644 --- a/vlib/net/socket.v +++ b/vlib/net/socket.v @@ -2,7 +2,7 @@ module net import os -struct Socket { +pub struct Socket { pub: sockfd int family int diff --git a/vlib/vweb/vweb.v b/vlib/vweb/vweb.v index 7a75f0828e..85fb778c7c 100644 --- a/vlib/vweb/vweb.v +++ b/vlib/vweb/vweb.v @@ -1,11 +1,15 @@ +// Copyright (c) 2019 Alexander Medvednikov. All rights reserved. +// Use of this source code is governed by an MIT license +// that can be found in the LICENSE file. + module vweb import ( os - net - http - net.urllib -) + net + http + net.urllib +) const ( methods_with_form = ['POST', 'PUT', 'PATCH'] @@ -27,16 +31,16 @@ const ( } ) -struct Context { - static_files map[string]string - static_mime_types map[string]string - pub: - req http.Request - conn net.Socket - form map[string]string - // TODO Response - mut: - headers string // response headers +pub struct Context { + static_files map[string]string + static_mime_types map[string]string +pub: + req http.Request + conn net.Socket + form map[string]string + // TODO Response +mut: + headers string // response headers } pub fn (ctx Context) html(html string) { @@ -48,11 +52,11 @@ pub fn (ctx Context) text(s string) { } pub fn (ctx Context) json(s string) { - ctx.conn.write('HTTP/1.1 200 OK\r\nContent-Type: application/json\r\n$ctx.headers\r\n\r\n$s') + ctx.conn.write('HTTP/1.1 200 OK\r\nContent-Type: application/json\r\n$ctx.headers\r\n\r\n$s') } pub fn (ctx Context) redirect(url string) { - ctx.conn.write('HTTP/1.1 302 Found\r\nLocation: $url\r\n\r\n$ctx.headers') + ctx.conn.write('HTTP/1.1 302 Found\r\nLocation: $url\r\n\r\n$ctx.headers') } pub fn (ctx Context) not_found(s string) { @@ -84,15 +88,16 @@ fn (ctx mut Context) get_header(key string) string { return ctx.headers.find_between('\r\n$key: ', '\r\n') } -pub fn run(port int) { - println('Running vweb app on http://localhost:$port ...') - l := net.listen(port) or { panic('failed to listen') } - mut app := T{} - app.init() +//pub fn run(port int) { +pub fn run(app T, port int) { + println('Running vweb app on http://localhost:$port ...') + l := net.listen(port) or { panic('failed to listen') } + //mut app := T{} + app.init() for { conn := l.accept() or { panic('accept() failed') - } + } //foobar() // TODO move this to handle_conn(conn, app) s := conn.read_line() @@ -123,35 +128,35 @@ pub fn run(port int) { ws_func: 0 user_ptr: 0 method: vals[0] - url: vals[1] - } + url: vals[1] + } $if debug { println('vweb action = "$action"') } //mut app := T{ app.vweb = Context{ - req: req - conn: conn + req: req + conn: conn form: map[string]string static_files: map[string]string static_mime_types: map[string]string - } - //} + } + //} if req.method in methods_with_form { - app.vweb.parse_form(s) - } + app.vweb.parse_form(s) + } if vals.len < 2 { $if debug { println('no vals for http') } conn.close() - continue - } + continue + } - // Serve a static file if it's one + // Serve a static file if it's one // if app.vweb.handle_static() { // conn.close() - // continue + // continue // } // Call the right action @@ -163,13 +168,13 @@ pub fn run(port int) { } -pub fn foobar() { -} +pub fn foobar() { +} -fn (ctx mut Context) parse_form(s string) { +fn (ctx mut Context) parse_form(s string) { if !(ctx.req.method in methods_with_form) { - return - } + return + } pos := s.index('\r\n\r\n') if pos > -1 { mut str_form := s.substr(pos, s.len) @@ -177,18 +182,18 @@ fn (ctx mut Context) parse_form(s string) { words := str_form.split('&') for word in words { $if debug { - println('parse form keyval="$word"') + println('parse form keyval="$word"') } - keyval := word.trim_space().split('=') - if keyval.len != 2 { continue } + keyval := word.trim_space().split('=') + if keyval.len != 2 { continue } key := keyval[0] val := urllib.query_unescape(keyval[1]) or { - continue + continue } - $if debug { - println('http form "$key" => "$val"') + $if debug { + println('http form "$key" => "$val"') } - ctx.form[key] = val + ctx.form[key] = val } } } @@ -227,15 +232,15 @@ pub fn (ctx mut Context) handle_static(directory_path string) bool { static_file := ctx.static_files[ctx.req.url] mime_type := ctx.static_mime_types[ctx.req.url] - if static_file != '' { - data := os.read_file(static_file) or { return false } + if static_file != '' { + data := os.read_file(static_file) or { return false } ctx.conn.write('HTTP/1.1 200 OK\r\nContent-Type: $mime_type\r\n\r\n$data') - return true - } - return false -} + return true + } + return false +} pub fn (ctx mut Context) serve_static(url, file_path, mime_type string) { - ctx.static_files[url] = file_path + ctx.static_files[url] = file_path ctx.static_mime_types[url] = mime_type }