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