vh generation: consts + cleanup
parent
fcead2f79e
commit
8b74c711c6
|
@ -289,16 +289,24 @@ fn os_name_to_ifdef(name string) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn platform_postfix_to_ifdefguard(name string) string {
|
fn platform_postfix_to_ifdefguard(name string) string {
|
||||||
switch name {
|
s := match name {
|
||||||
case '.v': return '' // no guard needed
|
'.v' { '' }// no guard needed
|
||||||
case '_win.v': return '#ifdef _WIN32'
|
'_win.v', '_windows.v' { '#ifdef _WIN32' }
|
||||||
case '_nix.v': return '#ifndef _WIN32'
|
'_nix.v' { '#ifndef _WIN32' }
|
||||||
case '_lin.v': return '#ifdef __linux__'
|
'_lin.v', '_linux.v' { '#ifdef __linux__' }
|
||||||
case '_mac.v': return '#ifdef __APPLE__'
|
'_mac.v', '_darwin.v' { '#ifdef __APPLE__' }
|
||||||
case '_solaris.v': return '#ifdef __sun'
|
'_solaris.v' { '#ifdef __sun' }
|
||||||
|
else {
|
||||||
|
|
||||||
|
//verror('bad platform_postfix "$name"')
|
||||||
|
// TODO
|
||||||
|
''
|
||||||
|
}
|
||||||
}
|
}
|
||||||
verror('bad platform_postfix "$name"')
|
if s == '' {
|
||||||
return ''
|
verror('bad platform_postfix "$name"')
|
||||||
|
}
|
||||||
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
// C struct definitions, ordered
|
// C struct definitions, ordered
|
||||||
|
|
|
@ -111,6 +111,7 @@ pub mut:
|
||||||
// to increase compilation time.
|
// to increase compilation time.
|
||||||
// This is on by default, since a vast majority of users do not
|
// This is on by default, since a vast majority of users do not
|
||||||
// work on the builtin module itself.
|
// work on the builtin module itself.
|
||||||
|
//generating_vh bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Should be called by main at the end of the compilation process, to cleanup
|
// Should be called by main at the end of the compilation process, to cleanup
|
||||||
|
@ -833,7 +834,7 @@ pub fn new_v(args[]string) &V {
|
||||||
out_name = dir.left(dir.len - 2)
|
out_name = dir.left(dir.len - 2)
|
||||||
// Building V? Use v2, since we can't overwrite a running
|
// Building V? Use v2, since we can't overwrite a running
|
||||||
// executable on Windows + the precompiled V is more
|
// executable on Windows + the precompiled V is more
|
||||||
// optimized.
|
// optimized.
|
||||||
if out_name == 'v' && os.dir_exists('vlib/compiler') {
|
if out_name == 'v' && os.dir_exists('vlib/compiler') {
|
||||||
println('Saving the resulting V executable in `./v2`')
|
println('Saving the resulting V executable in `./v2`')
|
||||||
println('Use `v -o v v.v` if you want to replace current '+
|
println('Use `v -o v v.v` if you want to replace current '+
|
||||||
|
|
|
@ -15,108 +15,6 @@ import (
|
||||||
They are used together with pre-compiled modules.
|
They are used together with pre-compiled modules.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// "fn foo(a int) string"
|
|
||||||
fn (f &Fn) v_definition() string {
|
|
||||||
//t :=time.ticks()
|
|
||||||
mut sb := strings.new_builder(100)
|
|
||||||
if f.is_public {
|
|
||||||
sb.write('pub ')
|
|
||||||
}
|
|
||||||
sb.write('fn ')
|
|
||||||
if f.is_c {
|
|
||||||
sb.write('C.')
|
|
||||||
}
|
|
||||||
if f.is_method {
|
|
||||||
recv := f.args[0]
|
|
||||||
typ := v_type_str(recv.typ).replace('*', '')
|
|
||||||
mut mu := if recv.is_mut { 'mut' } else { '' }
|
|
||||||
if recv.ref {
|
|
||||||
mu = '&'
|
|
||||||
}
|
|
||||||
sb.write('($recv.name $mu $typ) ')
|
|
||||||
}
|
|
||||||
if f.name.contains('__') {
|
|
||||||
sb.write(f.name.all_after('__') + '(')
|
|
||||||
} else {
|
|
||||||
sb.write('$f.name(')
|
|
||||||
}
|
|
||||||
for i, arg in f.args {
|
|
||||||
if i == 0 && f.is_method { // skip the receiver
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
typ := v_type_str(arg.typ).replace('*', '&')
|
|
||||||
if arg.name == '' {
|
|
||||||
sb.write(typ)
|
|
||||||
} else {
|
|
||||||
sb.write('$arg.name $typ')
|
|
||||||
}
|
|
||||||
if i != f.args.len - 1 {
|
|
||||||
sb.write(', ')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sb.write(')')
|
|
||||||
if f.typ != 'void' {
|
|
||||||
typ := v_type_str(f.typ).replace('*', '&')
|
|
||||||
sb.write(' ')
|
|
||||||
sb.write(typ)
|
|
||||||
sb.writeln(' ')
|
|
||||||
}
|
|
||||||
//println('ms: ${time.ticks() - t}')
|
|
||||||
return sb.str()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn v_type_str(typ_ string) string {
|
|
||||||
mut typ := if typ_.ends_with('*') {
|
|
||||||
'*' + typ_.left(typ_.len - 1)
|
|
||||||
} else {
|
|
||||||
typ_
|
|
||||||
}
|
|
||||||
typ = typ.replace('Option_', '?')
|
|
||||||
// fn parent/alias?
|
|
||||||
if typ.starts_with('fn ') {
|
|
||||||
mut types := []string
|
|
||||||
fi_lpar := typ.index_byte(`(`)
|
|
||||||
li_rpar := typ.last_index_byte(`)`)
|
|
||||||
ret_type := typ.right(li_rpar+1)
|
|
||||||
for t in typ.substr(fi_lpar+1, li_rpar).split(',') {
|
|
||||||
types << v_type_str(t)
|
|
||||||
}
|
|
||||||
return 'fn (' + types.join(', ') + ')$ret_type'
|
|
||||||
}
|
|
||||||
typ = typ.replace('Option_', '?')
|
|
||||||
// multiple return
|
|
||||||
if typ.contains('_V_MulRet') {
|
|
||||||
words := typ.replace('_V_MulRet_', '').replace('_PTR_', '*').split('_V_')
|
|
||||||
typ = '('
|
|
||||||
for i in 0 .. words.len {
|
|
||||||
typ += v_type_str(words[i])
|
|
||||||
if i != words.len - 1 {
|
|
||||||
typ += ','
|
|
||||||
}
|
|
||||||
}
|
|
||||||
typ += ')'
|
|
||||||
return typ
|
|
||||||
}
|
|
||||||
//println('"$typ"')
|
|
||||||
if typ == '*void' {
|
|
||||||
return 'voidptr'
|
|
||||||
}
|
|
||||||
if typ == '*byte' {
|
|
||||||
return 'byteptr'
|
|
||||||
}
|
|
||||||
if typ.starts_with('array_') {
|
|
||||||
return '[]' + typ.right(6)
|
|
||||||
}
|
|
||||||
if typ.contains('__') {
|
|
||||||
opt := typ.starts_with('?')
|
|
||||||
typ = typ.all_after('__')
|
|
||||||
if opt {
|
|
||||||
typ = '?' + typ
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return typ
|
|
||||||
}
|
|
||||||
|
|
||||||
// `mod` == "vlib/os"
|
// `mod` == "vlib/os"
|
||||||
fn generate_vh(mod string) {
|
fn generate_vh(mod string) {
|
||||||
println('\n\n\n\nGenerating a V header file for module `$mod`')
|
println('\n\n\n\nGenerating a V header file for module `$mod`')
|
||||||
|
@ -145,6 +43,8 @@ fn generate_vh(mod string) {
|
||||||
//v.pref.generating_vh = true
|
//v.pref.generating_vh = true
|
||||||
for file in filtered {
|
for file in filtered {
|
||||||
mut p := v.new_parser_from_file(file)
|
mut p := v.new_parser_from_file(file)
|
||||||
|
p.scanner.is_vh = true
|
||||||
|
println('kek $file')
|
||||||
p.parse(.decl)
|
p.parse(.decl)
|
||||||
for i, tok in p.tokens {
|
for i, tok in p.tokens {
|
||||||
if !p.tok.is_decl() {
|
if !p.tok.is_decl() {
|
||||||
|
@ -187,10 +87,23 @@ fn generate_fn(file os.File, tokens []Token, i int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_const(file os.File, tokens []Token, i int) {
|
fn generate_const(file os.File, tokens []Token, i int) {
|
||||||
//mut out := strings.new_builder(100)
|
mut out := strings.new_builder(100)
|
||||||
|
mut tok := tokens[i]
|
||||||
|
for i < tokens.len && tok.tok != .rpar {
|
||||||
|
out.write(tok.str())
|
||||||
|
out.write(' ')
|
||||||
|
if tokens[i+2].tok == .assign {
|
||||||
|
out.write('\n\t')
|
||||||
|
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
tok = tokens[i]
|
||||||
|
}
|
||||||
|
out.writeln('\n)')
|
||||||
|
file.writeln(out.str())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
fn (v &V) generate_vh_old() {
|
fn (v &V) generate_vh_old() {
|
||||||
println('\n\n\n\nGenerating a V header file for module `$v.mod`')
|
println('\n\n\n\nGenerating a V header file for module `$v.mod`')
|
||||||
mod_path := v.mod.replace('.', os.path_separator)
|
mod_path := v.mod.replace('.', os.path_separator)
|
||||||
|
@ -333,4 +246,5 @@ fn (v &V) generate_vh_old() {
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ struct Token {
|
||||||
struct Parser {
|
struct Parser {
|
||||||
file_path_id string // unique id. if parsing file will be path eg, "/home/user/hello.v"
|
file_path_id string // unique id. if parsing file will be path eg, "/home/user/hello.v"
|
||||||
file_name string // "hello.v"
|
file_name string // "hello.v"
|
||||||
file_platform string // ".v", "_win.v", "_nix.v", "_mac.v", "_lin.v" ...
|
file_platform string // ".v", "_windows.v", "_nix.v", "_darwin.v", "_linux.v" ...
|
||||||
// When p.file_pcguard != '', it contains a
|
// When p.file_pcguard != '', it contains a
|
||||||
// C ifdef guard clause that must be put before
|
// C ifdef guard clause that must be put before
|
||||||
// the #include directives in the parsed .v file
|
// the #include directives in the parsed .v file
|
||||||
|
@ -106,8 +106,21 @@ fn (v mut V) new_parser_from_file(path string) Parser {
|
||||||
//println('new_parser("$path")')
|
//println('new_parser("$path")')
|
||||||
mut path_pcguard := ''
|
mut path_pcguard := ''
|
||||||
mut path_platform := '.v'
|
mut path_platform := '.v'
|
||||||
for path_ending in ['_lin.v', '_mac.v', '_win.v', '_nix.v'] {
|
for path_ending in ['_lin.v', '_mac.v', '_win.v', '_nix.v', '_linux.v',
|
||||||
|
'_darwin.v', '_windows.v'] {
|
||||||
if path.ends_with(path_ending) {
|
if path.ends_with(path_ending) {
|
||||||
|
if path_ending == '_mac.v' {
|
||||||
|
p := path_ending.replace('_mac.v', '_darwin.v')
|
||||||
|
println('warning: use "$p" file name instead of "$path"')
|
||||||
|
}
|
||||||
|
if path_ending == '_lin.v' {
|
||||||
|
p := path_ending.replace('_lin.v', '_linux.v')
|
||||||
|
println('warning: use "$p" file name instead of "$path"')
|
||||||
|
}
|
||||||
|
if path_ending == '_win.v' {
|
||||||
|
p := path_ending.replace('_win.v', '_windows.v')
|
||||||
|
println('warning: use "$p" file name instead of "$path"')
|
||||||
|
}
|
||||||
path_platform = path_ending
|
path_platform = path_ending
|
||||||
path_pcguard = platform_postfix_to_ifdefguard( path_ending )
|
path_pcguard = platform_postfix_to_ifdefguard( path_ending )
|
||||||
break
|
break
|
||||||
|
@ -124,6 +137,10 @@ fn (v mut V) new_parser_from_file(path string) Parser {
|
||||||
if p.pref.building_v {
|
if p.pref.building_v {
|
||||||
p.scanner.should_print_relative_paths_on_error = true
|
p.scanner.should_print_relative_paths_on_error = true
|
||||||
}
|
}
|
||||||
|
//if p.pref.generating_vh {
|
||||||
|
// Keep newlines
|
||||||
|
//p.scanner.is_vh = true
|
||||||
|
//}
|
||||||
p.scan_tokens()
|
p.scan_tokens()
|
||||||
//p.scanner.debug_tokens()
|
//p.scanner.debug_tokens()
|
||||||
return p
|
return p
|
||||||
|
|
|
@ -41,6 +41,7 @@ mut:
|
||||||
quote byte // which quote is used to denote current string: ' or "
|
quote byte // which quote is used to denote current string: ' or "
|
||||||
line_ends []int // the positions of source lines ends (i.e. \n signs)
|
line_ends []int // the positions of source lines ends (i.e. \n signs)
|
||||||
nlines int // total number of lines in the source file that were scanned
|
nlines int // total number of lines in the source file that were scanned
|
||||||
|
is_vh bool // Keep newlines
|
||||||
}
|
}
|
||||||
|
|
||||||
// new scanner from file.
|
// new scanner from file.
|
||||||
|
@ -221,7 +222,12 @@ fn (s mut Scanner) ident_number() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (s mut Scanner) skip_whitespace() {
|
fn (s mut Scanner) skip_whitespace() {
|
||||||
|
//if s.is_vh { println('vh') return }
|
||||||
for s.pos < s.text.len && s.text[s.pos].is_white() {
|
for s.pos < s.text.len && s.text[s.pos].is_white() {
|
||||||
|
if is_nl(s.text[s.pos]) && s.is_vh {
|
||||||
|
return
|
||||||
|
|
||||||
|
}
|
||||||
// Count \r\n as one line
|
// Count \r\n as one line
|
||||||
if is_nl(s.text[s.pos]) && !s.expect('\r\n', s.pos-1) {
|
if is_nl(s.text[s.pos]) && !s.expect('\r\n', s.pos-1) {
|
||||||
s.inc_line_number()
|
s.inc_line_number()
|
||||||
|
@ -231,10 +237,10 @@ fn (s mut Scanner) skip_whitespace() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (s mut Scanner) scan() ScanRes {
|
fn (s mut Scanner) scan() ScanRes {
|
||||||
if s.line_comment != '' {
|
//if s.line_comment != '' {
|
||||||
//s.fgenln('// LOL "$s.line_comment"')
|
//s.fgenln('// LC "$s.line_comment"')
|
||||||
//s.line_comment = ''
|
//s.line_comment = ''
|
||||||
}
|
//}
|
||||||
if s.started {
|
if s.started {
|
||||||
s.pos++
|
s.pos++
|
||||||
}
|
}
|
||||||
|
@ -242,13 +248,12 @@ fn (s mut Scanner) scan() ScanRes {
|
||||||
if s.pos >= s.text.len {
|
if s.pos >= s.text.len {
|
||||||
return scan_res(.eof, '')
|
return scan_res(.eof, '')
|
||||||
}
|
}
|
||||||
// skip whitespace
|
|
||||||
if !s.inside_string {
|
if !s.inside_string {
|
||||||
s.skip_whitespace()
|
s.skip_whitespace()
|
||||||
}
|
}
|
||||||
// End of $var, start next string
|
// End of $var, start next string
|
||||||
if s.inter_end {
|
if s.inter_end {
|
||||||
if s.text[s.pos] == s.quote { //single_quote {
|
if s.text[s.pos] == s.quote {
|
||||||
s.inter_end = false
|
s.inter_end = false
|
||||||
return scan_res(.str, '')
|
return scan_res(.str, '')
|
||||||
}
|
}
|
||||||
|
@ -419,6 +424,7 @@ fn (s mut Scanner) scan() ScanRes {
|
||||||
s.error('@ must be used before keywords (e.g. `@type string`)')
|
s.error('@ must be used before keywords (e.g. `@type string`)')
|
||||||
}
|
}
|
||||||
return scan_res(.name, name)
|
return scan_res(.name, name)
|
||||||
|
/*
|
||||||
case `\r`:
|
case `\r`:
|
||||||
if nextc == `\n` {
|
if nextc == `\n` {
|
||||||
s.pos++
|
s.pos++
|
||||||
|
@ -428,6 +434,7 @@ fn (s mut Scanner) scan() ScanRes {
|
||||||
case `\n`:
|
case `\n`:
|
||||||
s.last_nl_pos = s.pos
|
s.last_nl_pos = s.pos
|
||||||
return scan_res(.nl, '')
|
return scan_res(.nl, '')
|
||||||
|
*/
|
||||||
case `.`:
|
case `.`:
|
||||||
if nextc == `.` {
|
if nextc == `.` {
|
||||||
s.pos++
|
s.pos++
|
||||||
|
@ -783,6 +790,7 @@ fn is_name_char(c byte) bool {
|
||||||
return c.is_letter() || c == `_`
|
return c.is_letter() || c == `_`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[inline]
|
||||||
fn is_nl(c byte) bool {
|
fn is_nl(c byte) bool {
|
||||||
return c == `\r` || c == `\n`
|
return c == `\r` || c == `\n`
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue