diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index 6b7c8c2d95..4bab48d058 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -782,7 +782,8 @@ pub: method_name string left Expr is_vweb bool - vweb_stmts []Stmt + // vweb_stmts []Stmt + vweb_tmpl File pub mut: sym table.TypeSymbol } diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index d9f14f6158..b932cfe411 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -1829,6 +1829,10 @@ pub fn (mut c Checker) expr(node ast.Expr) table.Type { } ast.ComptimeCall { it.sym = c.table.get_type_symbol(c.unwrap_generic(c.expr(it.left))) + if it.is_vweb { + mut c2 := new_checker(c.table, c.pref) + c2.check(it.vweb_tmpl) + } return table.void_type } ast.ConcatExpr { diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index 7189795442..5f5a3578ad 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -4351,6 +4351,16 @@ fn (mut g Gen) interface_call(typ, interface_type table.Type) { fn (g &Gen) comptime_call(node ast.ComptimeCall) { if node.is_vweb { + for stmt in node.vweb_tmpl.stmts { + if stmt is ast.FnDecl { + fn_decl := stmt as ast.FnDecl + // insert stmts from vweb_tmpl fn + if fn_decl.name == 'vweb_tmpl' { + g.stmts(fn_decl.stmts) + break + } + } + } g.writeln('vweb__Context_html(&app-> vweb, tmpl_res)') return } diff --git a/vlib/v/parser/comptime.v b/vlib/v/parser/comptime.v index 6d390f6e15..fd7fa10133 100644 --- a/vlib/v/parser/comptime.v +++ b/vlib/v/parser/comptime.v @@ -9,7 +9,6 @@ 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', @@ -78,60 +77,31 @@ 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) - 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) + mut scope := &ast.Scope{ + start_pos: 0 + parent: 0 + } + file := parse_text(v_code, p.table, scope, p.global_scope) if p.pref.is_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, @@ -143,15 +113,9 @@ fn (mut p Parser) vweb() ast.ComptimeCall { } } */ - 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 + vweb_tmpl: file } } diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index cabddfa9e5..3ed4e47955 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -75,6 +75,20 @@ pub fn parse_stmt(text string, table &table.Table, scope &ast.Scope) ast.Stmt { return p.stmt() } +pub fn parse_text(text string, b_table &table.Table, scope &ast.Scope, global_scope &ast.Scope) ast.File { + s := scanner.new_scanner(text, .skip_comments) + mut p := Parser{ + scanner: s + table: b_table + pref: &pref.Preferences{} + scope: scope + errors: []errors.Error{} + warnings: []errors.Warning{} + global_scope: global_scope + } + return p.parse() +} + pub fn parse_file(path string, b_table &table.Table, comments_mode scanner.CommentsMode, pref &pref.Preferences, global_scope &ast.Scope) ast.File { // NB: when comments_mode == .toplevel_comments, // the parser gives feedback to the scanner about toplevel statements, so that the scanner can skip @@ -85,7 +99,6 @@ pub fn parse_file(path string, b_table &table.Table, comments_mode scanner.Comme // text := os.read_file(path) or { // panic(err) // } - mut stmts := []ast.Stmt{} mut p := Parser{ scanner: scanner.new_scanner_file(path, comments_mode) comments_mode: comments_mode @@ -101,17 +114,20 @@ pub fn parse_file(path string, b_table &table.Table, comments_mode scanner.Comme warnings: []errors.Warning{} global_scope: global_scope } + return p.parse() +} + +fn (mut p Parser) parse() ast.File { // comments_mode: comments_mode p.init_parse_fns() p.read_first_token() + mut stmts := []ast.Stmt{} for p.tok.kind == .comment { stmts << p.comment() } // module - mut mstmt := ast.Stmt{} module_decl := p.module_decl() - mstmt = module_decl - stmts << mstmt + stmts << module_decl // imports for p.tok.kind == .key_import { stmts << p.import_stmt() @@ -137,7 +153,7 @@ pub fn parse_file(path string, b_table &table.Table, comments_mode scanner.Comme p.scope.end_pos = p.tok.pos // return ast.File{ - path: path + path: p.file_name mod: module_decl imports: p.ast_imports stmts: stmts diff --git a/vlib/vweb/tmpl/tmpl.v b/vlib/vweb/tmpl/tmpl.v index 1f950b2e8d..94afe8c07e 100644 --- a/vlib/vweb/tmpl/tmpl.v +++ b/vlib/vweb/tmpl/tmpl.v @@ -34,7 +34,9 @@ pub fn compile_template(content string) string { mut s := strings.new_builder(1000) // base := path.all_after_last('/').replace('.html', '') s.writeln(" + import strings // === vweb html template === + fn vweb_tmpl() { mut sb := strings.new_builder(${lines.len * 30}) header := \' \' // TODO remove _ = header @@ -90,6 +92,7 @@ pub fn compile_template(content string) string { } s.writeln(str_end) s.writeln('tmpl_res := sb.str() ') + s.writeln('}') s.writeln('// === end of vweb html template ===') return s.str() }