all: comptime_call - simplify tmpl scoping, solves many issues.
parent
6425000ce4
commit
8dc2601080
|
@ -124,6 +124,7 @@ mut:
|
||||||
inside_println_arg bool
|
inside_println_arg bool
|
||||||
inside_decl_rhs bool
|
inside_decl_rhs bool
|
||||||
inside_if_guard bool // true inside the guard condition of `if x := opt() {}`
|
inside_if_guard bool // true inside the guard condition of `if x := opt() {}`
|
||||||
|
vweb_comptime_call_pos int // needed for correctly checking use before decl for vweb templates
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_checker(table &ast.Table, pref &pref.Preferences) &Checker {
|
pub fn new_checker(table &ast.Table, pref &pref.Preferences) &Checker {
|
||||||
|
@ -3104,9 +3105,15 @@ pub fn (mut c Checker) ident(mut node ast.Ident) ast.Type {
|
||||||
return obj.typ
|
return obj.typ
|
||||||
}
|
}
|
||||||
ast.Var {
|
ast.Var {
|
||||||
// incase var was not marked as used yet (vweb tmpl)
|
// inside vweb tmpl ident positions are meaningless, use the position of the comptime call.
|
||||||
// obj.is_used = true
|
// if the variable is declared before the comptime call then we can assume all is well.
|
||||||
if node.pos.pos < obj.pos.pos {
|
// `node.name !in node.scope.objects` checks it's an inherited var (not defined in the tmpl).
|
||||||
|
node_pos := if c.pref.is_vweb && node.name !in node.scope.objects {
|
||||||
|
c.vweb_comptime_call_pos
|
||||||
|
} else {
|
||||||
|
node.pos.pos
|
||||||
|
}
|
||||||
|
if node_pos < obj.pos.pos {
|
||||||
c.error('undefined variable `$node.name` (used before declaration)',
|
c.error('undefined variable `$node.name` (used before declaration)',
|
||||||
node.pos)
|
node.pos)
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,28 +36,8 @@ fn (mut c Checker) comptime_call(mut node ast.ComptimeCall) ast.Type {
|
||||||
is_vweb: true
|
is_vweb: true
|
||||||
}
|
}
|
||||||
mut c2 := new_checker(c.table, pref2)
|
mut c2 := new_checker(c.table, pref2)
|
||||||
|
c2.vweb_comptime_call_pos = node.pos.pos
|
||||||
c2.check(node.vweb_tmpl)
|
c2.check(node.vweb_tmpl)
|
||||||
mut caller_scope := c.fn_scope.innermost(node.pos.pos)
|
|
||||||
mut i := 0 // tmp counter var for skipping first three tmpl vars
|
|
||||||
for k, _ in c2.file.scope.children[0].objects {
|
|
||||||
if i < 2 {
|
|
||||||
// Skip first three because they are tmpl vars see vlib/vweb/tmpl/tmpl.v
|
|
||||||
i++
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
tmpl_obj := unsafe { c2.file.scope.children[0].objects[k] }
|
|
||||||
if tmpl_obj is ast.Var {
|
|
||||||
if mut caller_var := caller_scope.find_var(tmpl_obj.name) {
|
|
||||||
// var is used in the tmpl so mark it as used in the caller
|
|
||||||
caller_var.is_used = true
|
|
||||||
// update props from the caller scope var to the tmpl scope var
|
|
||||||
c2.file.scope.children[0].objects[k] = ast.Var{
|
|
||||||
...(*caller_var)
|
|
||||||
pos: tmpl_obj.pos
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
c.warnings << c2.warnings
|
c.warnings << c2.warnings
|
||||||
c.errors << c2.errors
|
c.errors << c2.errors
|
||||||
c.notices << c2.notices
|
c.notices << c2.notices
|
||||||
|
|
|
@ -3697,10 +3697,8 @@ fn (mut g Gen) ident(node ast.Ident) {
|
||||||
g.write('${name}.val')
|
g.write('${name}.val')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// TODO: investigate why node.obj is pointing to outdated ScopeObject?
|
v := node.obj
|
||||||
// v := node.obj
|
if v is ast.Var {
|
||||||
// if v is ast.Var {
|
|
||||||
if v := node.scope.find_var(node.name) {
|
|
||||||
is_auto_heap = v.is_auto_heap && (!g.is_assign_lhs || g.assign_op != .decl_assign)
|
is_auto_heap = v.is_auto_heap && (!g.is_assign_lhs || g.assign_op != .decl_assign)
|
||||||
if is_auto_heap {
|
if is_auto_heap {
|
||||||
g.write('(*(')
|
g.write('(*(')
|
||||||
|
|
|
@ -245,10 +245,6 @@ fn (mut p Parser) comptime_call() ast.ComptimeCall {
|
||||||
println('$path:${i + 1}: $line')
|
println('$path:${i + 1}: $line')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mut scope := &ast.Scope{
|
|
||||||
start_pos: 0
|
|
||||||
parent: p.table.global_scope
|
|
||||||
}
|
|
||||||
$if trace_comptime ? {
|
$if trace_comptime ? {
|
||||||
println('')
|
println('')
|
||||||
println('>>> template for $path:')
|
println('>>> template for $path:')
|
||||||
|
@ -256,25 +252,11 @@ fn (mut p Parser) comptime_call() ast.ComptimeCall {
|
||||||
println('>>> end of template END')
|
println('>>> end of template END')
|
||||||
println('')
|
println('')
|
||||||
}
|
}
|
||||||
mut file := parse_comptime(v_code, p.table, p.pref, scope)
|
// the tmpl inherits all parent scopes. previous functionality was just to
|
||||||
|
// inherit the scope from which the comptime call was made and no parents.
|
||||||
|
// this is much simpler and allws access to globals. can be changed if needed.
|
||||||
|
mut file := parse_comptime(tmpl_path, v_code, p.table, p.pref, p.scope)
|
||||||
file.path = tmpl_path
|
file.path = tmpl_path
|
||||||
// copy vars from current fn scope into vweb_tmpl scope
|
|
||||||
for mut stmt in file.stmts {
|
|
||||||
if mut stmt is ast.FnDecl {
|
|
||||||
if stmt.name == 'main.vweb_tmpl_$tmp_fn_name' {
|
|
||||||
for _, mut obj in p.scope.objects {
|
|
||||||
if mut obj is ast.Var {
|
|
||||||
stmt.scope.register(ast.Var{
|
|
||||||
...obj
|
|
||||||
is_used: true
|
|
||||||
pos: stmt.body_pos
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ast.ComptimeCall{
|
return ast.ComptimeCall{
|
||||||
scope: 0
|
scope: 0
|
||||||
is_vweb: true
|
is_vweb: true
|
||||||
|
|
|
@ -115,11 +115,12 @@ pub fn parse_stmt(text string, table &ast.Table, scope &ast.Scope) ast.Stmt {
|
||||||
return p.stmt(false)
|
return p.stmt(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_comptime(text string, table &ast.Table, pref &pref.Preferences, scope &ast.Scope) &ast.File {
|
pub fn parse_comptime(tmpl_path string, text string, table &ast.Table, pref &pref.Preferences, scope &ast.Scope) &ast.File {
|
||||||
$if trace_parse_comptime ? {
|
$if trace_parse_comptime ? {
|
||||||
eprintln('> ${@MOD}.${@FN} text: $text')
|
eprintln('> ${@MOD}.${@FN} text: $text')
|
||||||
}
|
}
|
||||||
mut p := Parser{
|
mut p := Parser{
|
||||||
|
file_name: tmpl_path
|
||||||
scanner: scanner.new_scanner(text, .skip_comments, pref)
|
scanner: scanner.new_scanner(text, .skip_comments, pref)
|
||||||
table: table
|
table: table
|
||||||
pref: pref
|
pref: pref
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
$a.name
|
||||||
|
$b
|
|
@ -0,0 +1,11 @@
|
||||||
|
[heap]
|
||||||
|
struct MyHeapStruct {
|
||||||
|
name string
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sure dereferencing of heap stucts works in selector expr (in tmpl),
|
||||||
|
fn test_heap_struct_dereferencing_in_selector_expr() {
|
||||||
|
a := MyHeapStruct{name: 'my_heap_struct_a'}
|
||||||
|
b := 2
|
||||||
|
$tmpl('comptime_call_tmpl_variable_scope_test.tpl')
|
||||||
|
}
|
Loading…
Reference in New Issue