fix single file programs without `fn main` and REPL (allow imports,

function definitions, consts, etc)
pull/751/head
Alexander Medvednikov 2019-06-28 12:41:09 +02:00
parent fd9163f715
commit bd49977feb
5 changed files with 31 additions and 28 deletions

View File

@ -84,8 +84,8 @@ fn (f mut Fn) register_var(v Var) {
} }
else { else {
f.local_vars[f.var_idx] = new_var f.local_vars[f.var_idx] = new_var
f.var_idx++
} }
f.var_idx++
} }
// vlib header file? // vlib header file?

View File

@ -343,7 +343,7 @@ string _STR_TMP(const char *fmt, ...) {
if !c.table.main_exists() && !c.is_test { if !c.table.main_exists() && !c.is_test {
// It can be skipped in single file programs // It can be skipped in single file programs
if c.is_script { if c.is_script {
println('Generating main()...') //println('Generating main()...')
cgen.genln('int main() { $cgen.fn_main; return 0; }') cgen.genln('int main() { $cgen.fn_main; return 0; }')
} }
else { else {
@ -372,14 +372,14 @@ string _STR_TMP(const char *fmt, ...) {
cgen.genln('return 1; }') cgen.genln('return 1; }')
} }
cgen.save() cgen.save()
c.log('flags=')
if c.is_verbose { if c.is_verbose {
c.log('flags=')
println(c.table.flags) println(c.table.flags)
} }
c.cc() c.cc()
if c.is_test || c.is_run { if c.is_test || c.is_run {
if true || c.is_verbose { if true || c.is_verbose {
println('============running $c.out_name==============================') println('============ running $c.out_name ============')
} }
mut cmd := if c.out_name.starts_with('/') { mut cmd := if c.out_name.starts_with('/') {
c.out_name c.out_name
@ -866,10 +866,9 @@ fn run_repl() []string {
// but don't add this print call to the `lines` array, // but don't add this print call to the `lines` array,
// so that it doesn't get called during the next print. // so that it doesn't get called during the next print.
if line.starts_with('print') { if line.starts_with('print') {
// TODO remove this once files without main compile correctly
void_line := line.substr(line.index('(') + 1, line.len - 1) void_line := line.substr(line.index('(') + 1, line.len - 1)
lines << void_line lines << void_line
source_code := 'fn main(){' + lines.join('\n') + '\n' + line + '}' source_code := lines.join('\n') + '\n' + line
os.write_file(file, source_code) os.write_file(file, source_code)
mut v := new_v( ['v', '-repl', file]) mut v := new_v( ['v', '-repl', file])
v.compile() v.compile()

View File

@ -77,6 +77,7 @@ mut:
const ( const (
EmptyFn = &Fn { } EmptyFn = &Fn { }
MainFn= &Fn{name:'main'}
) )
fn (c mut V) new_parser(path string, run Pass) Parser { fn (c mut V) new_parser(path string, run Pass) Parser {
@ -225,7 +226,7 @@ fn (p mut Parser) parse() {
g += p.cgen.end_tmp() g += p.cgen.end_tmp()
} }
// p.genln('; // global') // p.genln('; // global')
g += ('; // global') g += '; // global'
p.cgen.consts << g p.cgen.consts << g
case EOF: case EOF:
p.log('end of parse()') p.log('end of parse()')
@ -238,25 +239,29 @@ fn (p mut Parser) parse() {
default: default:
// no `fn main`, add this "global" statement to cgen.fn_main // no `fn main`, add this "global" statement to cgen.fn_main
if p.is_script && !p.is_test { if p.is_script && !p.is_test {
if p.cur_fn.scope_level == 0 { // cur_fn is empty since there was no fn main declared
// p.cur_fn.scope_level++ // we need to set it to save and find variables
if p.first_run() {
if p.cur_fn.name == '' {
p.cur_fn = MainFn
}
return
}
if p.cur_fn.name == '' {
p.cur_fn = MainFn
} }
// println('is script')
p.print_tok()
start := p.cgen.lines.len start := p.cgen.lines.len
p.statement(true) p.statement(true)
p.genln('')
end := p.cgen.lines.len end := p.cgen.lines.len
lines := p.cgen.lines.slice(start, end) lines := p.cgen.lines.slice(start, end)
// p.cgen.fn_main << p.cgen.prev_line //mut line := p.cgen.fn_main + lines.join('\n')
// println('fn line:') //line = line.trim_space()
// println(p.cgen.fn_main + lines.join('\n'))
p.cgen.fn_main = p.cgen.fn_main + lines.join('\n') p.cgen.fn_main = p.cgen.fn_main + lines.join('\n')
p.cgen.cur_line = '' p.cgen.cur_line = ''
for i := start; i < end; i++ { for i := start; i < end; i++ {
// p.cgen.lines[p.cgen.lines.len - 1] = ''
p.cgen.lines[i] = '' p.cgen.lines[i] = ''
} }
// exit('')
} }
else { else {
p.error('unexpected token `${p.strtok()}`') p.error('unexpected token `${p.strtok()}`')
@ -664,13 +669,14 @@ fn (p mut Parser) error(s string) {
p.cgen.save() p.cgen.save()
// V git pull hint // V git pull hint
cur_path := os.getwd() cur_path := os.getwd()
if p.file_path.contains('v/compiler') || cur_path.contains('v/compiler') { if !p.is_repl && ( p.file_path.contains('v/compiler') || cur_path.contains('v/compiler') ){
println('\n=========================') println('\n=========================')
println('It looks like you are building V. It is being frequently updated every day.') println('It looks like you are building V. It is being frequently updated every day.')
println('If you didn\'t modify the compiler\'s code, most likely there was a change that ') println('If you didn\'t modify the compiler\'s code, most likely there was a change that ')
println('lead to this error.') println('lead to this error.')
println('\nTry to run `git pull && make clean && make`, that will most likely fix it.') println('\nRun `git pull && make`, that will most likely fix it.')
println('\nIf this doesn\'t help, re-install V from source or download a precompiled' + ' binary from\nhttps://vlang.io.') //println('\nIf this doesn\'t help, re-install V from source or download a precompiled' + ' binary from\nhttps://vlang.io.')
println('\nIf this doesn\'t help, please create a GitHub issue.')
println('=========================\n') println('=========================\n')
} }
// p.scanner.debug_tokens() // p.scanner.debug_tokens()
@ -1349,9 +1355,7 @@ fn (p mut Parser) name_expr() string {
// Function (not method btw, methods are handled in dot()) // Function (not method btw, methods are handled in dot())
f := p.table.find_fn(name) f := p.table.find_fn(name)
if f.name == '' { if f.name == '' {
println(p.cur_fn.name) // We are in a second pass, that means this function was not defined, throw an error.
println(p.cur_fn.args.len)
// if !p.first_run() && !p.translated {
if !p.first_run() { if !p.first_run() {
// println('name_expr():') // println('name_expr():')
// If orig_name is a pkg, then printing undefined: `pkg` tells us nothing // If orig_name is a pkg, then printing undefined: `pkg` tells us nothing

View File

@ -210,7 +210,7 @@ fn (table &Table) known_type(typ string) bool {
return false return false
} }
// TODO PERF O(N) this slows down the comiler a lot! // TODO PERF O(N) this slows down the compiler a lot!
fn (t &Table) find_fn(name string) Fn { fn (t &Table) find_fn(name string) Fn {
for f in t.fns { for f in t.fns {
if f.name == name { if f.name == name {
@ -220,7 +220,7 @@ fn (t &Table) find_fn(name string) Fn {
return Fn{} return Fn{}
} }
// TODO PERF O(N) this slows down the comiler a lot! // TODO PERF O(N) this slows down the compiler a lot!
fn (t &Table) known_fn(name string) bool { fn (t &Table) known_fn(name string) bool {
for f in t.fns { for f in t.fns {
if f.name == name { if f.name == name {
@ -249,10 +249,9 @@ fn (t mut Table) register_type(typ string) {
// if t.types.filter( _.name == typ.name).len > 0 { // if t.types.filter( _.name == typ.name).len > 0 {
// return // return
// } // }
datyp := Type { t.types << Type {
name: typ name: typ
} }
t.types << datyp
} }
fn (p mut Parser) register_type_with_parent(strtyp, parent string) { fn (p mut Parser) register_type_with_parent(strtyp, parent string) {

View File

@ -1 +1,2 @@
println('Hello, World!') println('Hello, World!')