176 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			V
		
	
	
			
		
		
	
	
			176 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			V
		
	
	
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
 | 
						|
// Use of this source code is governed by an MIT license
 | 
						|
// that can be found in the LICENSE file.
 | 
						|
 | 
						|
module compiler
 | 
						|
 | 
						|
import (
 | 
						|
	strings
 | 
						|
	os
 | 
						|
)
 | 
						|
 | 
						|
/*
 | 
						|
	.vh generation logic.
 | 
						|
	.vh files contain only function signatures, consts, and types.
 | 
						|
	They are used together with pre-compiled modules.
 | 
						|
*/
 | 
						|
 | 
						|
struct VhGen {
 | 
						|
mut:
 | 
						|
	i int // token index
 | 
						|
	consts strings.Builder
 | 
						|
	fns strings.Builder
 | 
						|
	types strings.Builder
 | 
						|
	tokens []Token
 | 
						|
	
 | 
						|
}	
 | 
						|
 | 
						|
// `mod` == "vlib/os"
 | 
						|
fn generate_vh(mod string) {
 | 
						|
	println('\n\n\n\n1Generating a V header file for module `$mod`')
 | 
						|
	vexe := os.executable()
 | 
						|
	full_mod_path := os.dir(vexe) + '/' + mod
 | 
						|
	mod_path := mod.replace('.', os.path_separator)
 | 
						|
	dir := if mod.starts_with('vlib') {
 | 
						|
		'$compiler.v_modules_path${os.path_separator}$mod'
 | 
						|
	} else {
 | 
						|
		'$compiler.v_modules_path${os.path_separator}$mod'
 | 
						|
	}
 | 
						|
	path := dir + '.vh'
 | 
						|
	pdir := dir.all_before_last(os.path_separator)
 | 
						|
	if !os.dir_exists(pdir) {
 | 
						|
		os.mkdir_all(pdir)
 | 
						|
		// os.mkdir(os.realpath(dir))
 | 
						|
	}
 | 
						|
	out := os.create(path) or { panic(err) }
 | 
						|
	mod_def := if mod.contains('/') { mod.all_after('/') } else { mod } // "os"
 | 
						|
	out.writeln('// $mod module header \n')
 | 
						|
	out.writeln('module $mod_def\n')
 | 
						|
	// Consts
 | 
						|
	println(full_mod_path)
 | 
						|
	mut vfiles := os.walk_ext(full_mod_path, '.v')
 | 
						|
	//mut vfiles := os.ls(full_mod_path) or {
 | 
						|
		//exit(1)
 | 
						|
	//}	
 | 
						|
	filtered := vfiles.filter(it.ends_with('.v') && !it.ends_with('test.v') &&
 | 
						|
		!it.ends_with('_windows.v') && !it.ends_with('_win.v') &&
 | 
						|
		!it.ends_with('_lin.v') &&
 | 
						|
		!it.contains('/examples') &&
 | 
						|
		!it.contains('_js.v') &&
 | 
						|
		!it.contains('/js')) // TODO merge once filter allows it
 | 
						|
	println('f:')
 | 
						|
	println(filtered)
 | 
						|
	mut v := new_v(['foo.v'])
 | 
						|
	//v.pref.generating_vh = true
 | 
						|
	mut g := VhGen{
 | 
						|
	 consts : strings.new_builder(1000)
 | 
						|
	 fns : strings.new_builder(1000)
 | 
						|
	 types : strings.new_builder(1000)
 | 
						|
	}
 | 
						|
	for file in filtered {
 | 
						|
		mut p := v.new_parser_from_file(file)
 | 
						|
		p.scanner.is_vh = true
 | 
						|
		p.parse(.decl)
 | 
						|
		g.tokens = p.tokens
 | 
						|
		g.i = 0
 | 
						|
		for ; g.i < p.tokens.len; g.i++ {
 | 
						|
			if !p.tokens[g.i].tok.is_decl() {
 | 
						|
				continue
 | 
						|
			}	
 | 
						|
			match g.tokens[g.i].tok {
 | 
						|
				.key_fn     {	g.generate_fn()    }
 | 
						|
				.key_const  {	g.generate_const() }
 | 
						|
				.key_struct {	g.generate_type()  }
 | 
						|
				.key_type   {	g.generate_alias() }
 | 
						|
			}	
 | 
						|
		}	
 | 
						|
	}	
 | 
						|
	result :=
 | 
						|
		g.types.str() +
 | 
						|
		g.consts.str() +
 | 
						|
		g.fns.str().replace('\n\n\n', '\n').replace('\n\n', '\n')
 | 
						|
	
 | 
						|
	out.writeln(result.replace('[ ] ', '[]').replace('? ', '?'))
 | 
						|
	out.close()
 | 
						|
}
 | 
						|
 | 
						|
fn (g mut VhGen) generate_fn() {
 | 
						|
	if g.i >= g.tokens.len - 2 {
 | 
						|
		return
 | 
						|
	}	
 | 
						|
	mut next := g.tokens[g.i+1]
 | 
						|
	if g.i > 0 && g.tokens[g.i-1].tok != .key_pub {
 | 
						|
		// Skip private fns
 | 
						|
		//return ''
 | 
						|
	}
 | 
						|
	
 | 
						|
	if next.tok == .name && next.lit == 'C' {
 | 
						|
		println('skipping C')
 | 
						|
		return
 | 
						|
	}	
 | 
						|
	//out.write('pub ')
 | 
						|
	mut tok := g.tokens[g.i]
 | 
						|
	for g.i < g.tokens.len - 1 && tok.tok != .lcbr {
 | 
						|
		next = g.tokens[g.i+1]
 | 
						|
		
 | 
						|
		g.fns.write(tok.str())
 | 
						|
		if tok.tok != .lpar  && !(next.tok in [.comma, .rpar]) {
 | 
						|
			// No space after (), [], etc
 | 
						|
			g.fns.write(' ')
 | 
						|
		}
 | 
						|
		g.i++
 | 
						|
		tok = g.tokens[g.i]
 | 
						|
	}	
 | 
						|
	g.fns.writeln('')
 | 
						|
	//g.i--
 | 
						|
}	
 | 
						|
 | 
						|
fn (g mut VhGen) generate_alias() {
 | 
						|
	mut tok := g.tokens[g.i]
 | 
						|
	for g.i < g.tokens.len-1 {
 | 
						|
		g.types.write(tok.str())
 | 
						|
		g.types.write(' ')
 | 
						|
		if tok.line_nr != g.tokens[g.i+1].line_nr {
 | 
						|
			break
 | 
						|
		}	
 | 
						|
		g.i++
 | 
						|
		tok = g.tokens[g.i]
 | 
						|
	}
 | 
						|
	g.types.writeln('\n')
 | 
						|
	//g.i--
 | 
						|
}
 | 
						|
 | 
						|
fn (g mut VhGen) generate_const() {
 | 
						|
	mut tok := g.tokens[g.i]
 | 
						|
	for g.i < g.tokens.len && tok.tok != .rpar {
 | 
						|
		g.consts.write(tok.str())
 | 
						|
		g.consts.write(' ')
 | 
						|
		if g.tokens[g.i+2].tok == .assign {
 | 
						|
			g.consts.write('\n\t')
 | 
						|
		}	
 | 
						|
		g.i++
 | 
						|
		tok = g.tokens[g.i]
 | 
						|
	}
 | 
						|
	g.consts.writeln('\n)')
 | 
						|
	//g.i--
 | 
						|
}
 | 
						|
 | 
						|
fn (g mut VhGen) generate_type() {
 | 
						|
	//old := g.i
 | 
						|
	mut tok := g.tokens[g.i]
 | 
						|
	for g.i < g.tokens.len && tok.tok != .rcbr {
 | 
						|
		g.types.write(tok.str())
 | 
						|
		g.types.write(' ')
 | 
						|
		if g.tokens[g.i+1].line_nr != g.tokens[g.i].line_nr {
 | 
						|
			g.types.write('\n\t')
 | 
						|
		}	
 | 
						|
		g.i++
 | 
						|
		tok = g.tokens[g.i]
 | 
						|
	}
 | 
						|
	g.types.writeln('\n}')
 | 
						|
	//g.i = old
 | 
						|
	//g.i--
 | 
						|
}
 | 
						|
 | 
						|
 |