diff --git a/examples/vweb/vweb_example.v b/examples/vweb/vweb_example.v index 4ddaa9a928..0476db7ddd 100644 --- a/examples/vweb/vweb_example.v +++ b/examples/vweb/vweb_example.v @@ -27,15 +27,15 @@ pub fn (mut app App) json_endpoint() { pub fn (mut app App) index() { app.cnt++ - app.vweb.text('Hello world from vweb') - //$vweb.html() + //app.vweb.text('Hello world from vweb') + $vweb.html() } pub fn (mut app App) reset() { } pub fn (mut app App) text() { - app.vweb.text('Hello world') + app.vweb.text('Hello world from vweb') } pub fn (mut app App) cookie() { diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index 1b0598ef87..6b7c8c2d95 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -781,6 +781,8 @@ pub struct ComptimeCall { pub: method_name string left Expr + is_vweb bool + vweb_stmts []Stmt pub mut: sym table.TypeSymbol } diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index eafb0063e6..7189795442 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -4350,6 +4350,10 @@ fn (mut g Gen) interface_call(typ, interface_type table.Type) { } fn (g &Gen) comptime_call(node ast.ComptimeCall) { + if node.is_vweb { + g.writeln('vweb__Context_html(&app-> vweb, tmpl_res)') + return + } g.writeln('// $' + 'method call. sym="$node.sym.name"') mut j := 0 for method in node.sym.methods { diff --git a/vlib/v/parser/comptime.v b/vlib/v/parser/comptime.v index 6fd75ca922..aa94157be6 100644 --- a/vlib/v/parser/comptime.v +++ b/vlib/v/parser/comptime.v @@ -8,6 +8,8 @@ import v.ast import v.pref import v.vmod import v.table +import vweb.tmpl +import v.token const ( supported_platforms = ['windows', 'mac', 'macos', 'darwin', 'linux', 'freebsd', 'openbsd', @@ -76,14 +78,81 @@ fn (mut p Parser) hash() ast.HashStmt { } } +struct ParserState { + scanner_pos int + tok token.Token + prev_tok token.Token + peek_tok token.Token + peek_tok2 token.Token + peek_tok3 token.Token +} + +pub fn (p &Parser) save_state() ParserState { + return ParserState{ + scanner_pos: p.scanner.pos + tok: p.tok + prev_tok: p.prev_tok + peek_tok: p.peek_tok + peek_tok2: p.peek_tok2 + peek_tok3: p.peek_tok3 + } +} + +pub fn (mut p Parser) restore_state(state ParserState) { + p.scanner.pos = state.scanner_pos + p.tok = state.tok + p.prev_tok = state.prev_tok + p.peek_tok = state.peek_tok + p.peek_tok2 = state.peek_tok2 + p.peek_tok3 = state.peek_tok3 +} + fn (mut p Parser) vweb() ast.ComptimeCall { p.check(.dollar) p.check(.name) // skip `vweb.html()` TODO p.check(.dot) + pos := p.scanner.pos p.check(.name) p.check(.lpar) p.check(.rpar) - return ast.ComptimeCall{} + state := p.save_state() + // Compile vweb html template to V code, parse that V code and embed the resulting V function + // that returns an html string. + mut path := p.cur_fn_name + '.html' + // if p.pref.is_debug { + println('>>> compiling vweb HTML template "$path"') + v_code := tmpl.compile_file(path) + if p.pref.verbose { + println('\n\n') + println('>>> vweb template for ${path}:') + println(v_code) + println('>>> end of vweb template END') + println('\n\n') + p.scanner.text = p.scanner.text[..pos] + v_code + p.scanner.text[pos..] + println(p.scanner.text) + } + // } + /* + if !os.exists(path) { + // Can't find the template file in current directory, + // try looking next to the vweb program, in case it's run with + // v path/to/vweb_app.v + path = os.dir(p.scanner.file_path) + '/' + path + if !os.exists(path) { + p.error('vweb HTML template "$path" not found') + } + } + */ + p.restore_state(state) + p.scanner.pos = pos + v_code.len + 1 + /* + println('restored:') + println(p.scanner.text[p.scanner.pos..]) + println('=============') + */ + return ast.ComptimeCall{ + is_vweb: true + } } fn (mut p Parser) comp_if() ast.Stmt { diff --git a/vlib/v/parser/fn.v b/vlib/v/parser/fn.v index fb366bfc11..0ac9b2109c 100644 --- a/vlib/v/parser/fn.v +++ b/vlib/v/parser/fn.v @@ -265,6 +265,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl { }) } // Body + p.cur_fn_name = name mut stmts := []ast.Stmt{} no_body := p.tok.kind != .lcbr body_start_pos := p.peek_tok.position() diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index a289ef46c0..cabddfa9e5 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -54,6 +54,7 @@ mut: expecting_type bool // `is Type`, expecting type errors []errors.Error warnings []errors.Warning + cur_fn_name string } // for tests diff --git a/vlib/vweb/tmpl/tmpl.v b/vlib/vweb/tmpl/tmpl.v index ac3a776efa..1f950b2e8d 100644 --- a/vlib/vweb/tmpl/tmpl.v +++ b/vlib/vweb/tmpl/tmpl.v @@ -34,10 +34,11 @@ pub fn compile_template(content string) string { mut s := strings.new_builder(1000) // base := path.all_after_last('/').replace('.html', '') s.writeln(" -mut sb := strings.new_builder(${lines.len * 30}) -header := \' \' // TODO remove -_ = header -//footer := \'footer\' + // === vweb html template === + mut sb := strings.new_builder(${lines.len * 30}) + header := \' \' // TODO remove + _ = header + //footer := \'footer\' ") s.writeln(str_start) mut in_css := true // false @@ -88,6 +89,7 @@ _ = header } } s.writeln(str_end) - s.writeln('tmpl_res := sb.str() }') + s.writeln('tmpl_res := sb.str() ') + s.writeln('// === end of vweb html template ===') return s.str() }