compiler: @FILE, @LINE, @FN, @COLUMN
parent
76a89c832e
commit
d5665997e0
|
@ -115,7 +115,7 @@ fn (p mut Parser) comp_time() {
|
||||||
os.rm('.vwebtmpl.v')
|
os.rm('.vwebtmpl.v')
|
||||||
}
|
}
|
||||||
pp.is_vweb = true
|
pp.is_vweb = true
|
||||||
pp.cur_fn = p.cur_fn // give access too all variables in current function
|
pp.set_current_fn( p.cur_fn ) // give access too all variables in current function
|
||||||
pp.parse(.main)
|
pp.parse(.main)
|
||||||
tmpl_fn_body := p.cgen.lines.slice(pos + 2, p.cgen.lines.len).join('\n').clone()
|
tmpl_fn_body := p.cgen.lines.slice(pos + 2, p.cgen.lines.len).join('\n').clone()
|
||||||
end_pos := tmpl_fn_body.last_index('Builder_str( sb )') + 19 // TODO
|
end_pos := tmpl_fn_body.last_index('Builder_str( sb )') + 19 // TODO
|
||||||
|
|
|
@ -284,7 +284,7 @@ fn (p mut Parser) fn_decl() {
|
||||||
''
|
''
|
||||||
}
|
}
|
||||||
if !p.is_vweb {
|
if !p.is_vweb {
|
||||||
p.cur_fn = f
|
p.set_current_fn( f )
|
||||||
}
|
}
|
||||||
// Generate `User_register()` instead of `register()`
|
// Generate `User_register()` instead of `register()`
|
||||||
// Internally it's still stored as "register" in type User
|
// Internally it's still stored as "register" in type User
|
||||||
|
@ -492,7 +492,7 @@ _thread_so = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)&reload_so, 0, 0, 0);
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
p.check_unused_variables()
|
p.check_unused_variables()
|
||||||
p.cur_fn = EmptyFn
|
p.set_current_fn( EmptyFn )
|
||||||
p.returns = false
|
p.returns = false
|
||||||
if !is_generic {
|
if !is_generic {
|
||||||
p.genln('}')
|
p.genln('}')
|
||||||
|
|
|
@ -119,6 +119,11 @@ fn (v mut V) new_parser(path string) Parser {
|
||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn (p mut Parser) set_current_fn(f &Fn) {
|
||||||
|
p.cur_fn = f
|
||||||
|
p.scanner.fn_name = '${f.mod}.${f.name}'
|
||||||
|
}
|
||||||
|
|
||||||
fn (p mut Parser) next() {
|
fn (p mut Parser) next() {
|
||||||
p.prev_tok2 = p.prev_tok
|
p.prev_tok2 = p.prev_tok
|
||||||
p.prev_tok = p.tok
|
p.prev_tok = p.tok
|
||||||
|
@ -262,7 +267,7 @@ fn (p mut Parser) parse(pass Pass) {
|
||||||
case Token.eof:
|
case Token.eof:
|
||||||
p.log('end of parse()')
|
p.log('end of parse()')
|
||||||
if p.is_script && !p.pref.is_test {
|
if p.is_script && !p.pref.is_test {
|
||||||
p.cur_fn = MainFn
|
p.set_current_fn( MainFn )
|
||||||
p.check_unused_variables()
|
p.check_unused_variables()
|
||||||
}
|
}
|
||||||
if false && !p.first_pass() && p.fileis('main.v') {
|
if false && !p.first_pass() && p.fileis('main.v') {
|
||||||
|
@ -281,12 +286,12 @@ fn (p mut Parser) parse(pass Pass) {
|
||||||
// we need to set it to save and find variables
|
// we need to set it to save and find variables
|
||||||
if p.first_pass() {
|
if p.first_pass() {
|
||||||
if p.cur_fn.name == '' {
|
if p.cur_fn.name == '' {
|
||||||
p.cur_fn = MainFn
|
p.set_current_fn( MainFn )
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if p.cur_fn.name == '' {
|
if p.cur_fn.name == '' {
|
||||||
p.cur_fn = MainFn
|
p.set_current_fn( MainFn )
|
||||||
if p.pref.is_repl {
|
if p.pref.is_repl {
|
||||||
p.cur_fn.clear_vars()
|
p.cur_fn.clear_vars()
|
||||||
}
|
}
|
||||||
|
@ -2532,16 +2537,28 @@ fn (p mut Parser) string_expr() {
|
||||||
// Custom format? ${t.hour:02d}
|
// Custom format? ${t.hour:02d}
|
||||||
custom := p.tok == .colon
|
custom := p.tok == .colon
|
||||||
if custom {
|
if custom {
|
||||||
format += '%'
|
mut cformat := ''
|
||||||
p.next()
|
p.next()
|
||||||
if p.tok == .dot {
|
if p.tok == .dot {
|
||||||
format += '.'
|
cformat += '.'
|
||||||
p.next()
|
p.next()
|
||||||
}
|
}
|
||||||
format += p.lit// 02
|
if p.tok == .minus { // support for left aligned formatting
|
||||||
|
cformat += '-'
|
||||||
|
p.next()
|
||||||
|
}
|
||||||
|
cformat += p.lit// 02
|
||||||
p.next()
|
p.next()
|
||||||
format += p.lit// f
|
fspec := p.lit // f
|
||||||
// println('custom str F=$format')
|
cformat += fspec
|
||||||
|
if fspec == 's' {
|
||||||
|
//println('custom str F=$cformat | format_specifier: "$fspec" | typ: $typ ')
|
||||||
|
if typ != 'string' {
|
||||||
|
p.error('only v strings can be formatted with a :${cformat} format, but you have given "${val}", which has type ${typ}.')
|
||||||
|
}
|
||||||
|
args = args.all_before_last('${val}.len, ${val}.str') + '${val}.str'
|
||||||
|
}
|
||||||
|
format += '%$cformat'
|
||||||
p.next()
|
p.next()
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -2563,6 +2580,7 @@ fn (p mut Parser) string_expr() {
|
||||||
}
|
}
|
||||||
format += f
|
format += f
|
||||||
}
|
}
|
||||||
|
//println('interpolation format is: |${format}| args are: |${args}| ')
|
||||||
}
|
}
|
||||||
if complex_inter {
|
if complex_inter {
|
||||||
p.fgen('}')
|
p.fgen('}')
|
||||||
|
|
|
@ -24,6 +24,7 @@ mut:
|
||||||
fmt_indent int
|
fmt_indent int
|
||||||
fmt_line_empty bool
|
fmt_line_empty bool
|
||||||
prev_tok Token
|
prev_tok Token
|
||||||
|
fn_name string // needed for @FN
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_scanner(file_path string) &Scanner {
|
fn new_scanner(file_path string) &Scanner {
|
||||||
|
@ -394,6 +395,17 @@ fn (s mut Scanner) scan() ScanRes {
|
||||||
case `@`:
|
case `@`:
|
||||||
s.pos++
|
s.pos++
|
||||||
name := s.ident_name()
|
name := s.ident_name()
|
||||||
|
// @FN => will be substituted with the name of the current V function
|
||||||
|
// @FILE => will be substituted with the path of the V source file
|
||||||
|
// @LINE => will be substituted with the V line number where it appears (as a string).
|
||||||
|
// @COLUMN => will be substituted with the column where it appears (as a string).
|
||||||
|
// This allows things like this:
|
||||||
|
// println( 'file: ' + @FILE + ' | line: ' + @LINE + ' | fn: ' + @FN)
|
||||||
|
// ... which is useful while debugging/tracing
|
||||||
|
if name == 'FN' { return scan_res(.str, s.fn_name) }
|
||||||
|
if name == 'FILE' { return scan_res(.str, os.realpath(s.file_path)) }
|
||||||
|
if name == 'LINE' { return scan_res(.str, (s.line_nr+1).str()) }
|
||||||
|
if name == 'COLUMN' { return scan_res(.str, (s.current_column()).str()) }
|
||||||
if !is_key(name) {
|
if !is_key(name) {
|
||||||
s.error('@ must be used before keywords (e.g. `@type string`)')
|
s.error('@ must be used before keywords (e.g. `@type string`)')
|
||||||
}
|
}
|
||||||
|
@ -580,9 +592,13 @@ fn (s &Scanner) find_current_line_start_position() int {
|
||||||
return linestart
|
return linestart
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn (s &Scanner) current_column() int {
|
||||||
|
return s.pos - s.find_current_line_start_position()
|
||||||
|
}
|
||||||
|
|
||||||
fn (s &Scanner) error(msg string) {
|
fn (s &Scanner) error(msg string) {
|
||||||
fullpath := os.realpath( s.file_path )
|
fullpath := os.realpath( s.file_path )
|
||||||
column := s.pos - s.find_current_line_start_position()
|
column := s.current_column()
|
||||||
// The filepath:line:col: format is the default C compiler
|
// The filepath:line:col: format is the default C compiler
|
||||||
// error output format. It allows editors and IDE's like
|
// error output format. It allows editors and IDE's like
|
||||||
// emacs to quickly find the errors in the output
|
// emacs to quickly find the errors in the output
|
||||||
|
|
Loading…
Reference in New Issue