run vfmt on parser.v

pull/3130/head
Alexander Medvednikov 2019-12-18 04:34:50 +03:00
parent ad211a86a6
commit a46a2e4715
2 changed files with 809 additions and 780 deletions

View File

@ -1,7 +1,6 @@
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved. // Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license // Use of this source code is governed by an MIT license
// that can be found in the LICENSE file. // that can be found in the LICENSE file.
module compiler module compiler
import ( import (
@ -83,10 +82,21 @@ pub mut:
const ( const (
max_module_depth = 5 max_module_depth = 5
reserved_types = { reserved_types = {
'i8' : true, 'i16' : true, 'int' : true, 'i64' : true, 'i128' : true, 'i8': true,
'byte' : true, 'u16' : true, 'u32' : true, 'u64' : true, 'u128' : true, 'i16': true,
'f32' : true, 'f64' : true, 'int': true,
'rune' : true, 'byteptr' : true, 'voidptr' : true 'i64': true,
'i128': true,
'byte': true,
'u16': true,
'u32': true,
'u64': true,
'u128': true,
'f32': true,
'f64': true,
'rune': true,
'byteptr': true,
'voidptr': true
} }
) )
@ -129,8 +139,7 @@ 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', '_linux.v', for path_ending in ['_lin.v', '_mac.v', '_win.v', '_nix.v', '_linux.v', '_darwin.v', '_windows.v'] {
'_darwin.v', '_windows.v'] {
if path.ends_with(path_ending) { if path.ends_with(path_ending) {
if path_ending == '_mac.v' { if path_ending == '_mac.v' {
p := path_ending.replace('_mac.v', '_darwin.v') p := path_ending.replace('_mac.v', '_darwin.v')
@ -149,10 +158,9 @@ fn (v mut V) new_parser_from_file(path string) Parser {
break break
} }
} }
mut p := v.new_parser(new_scanner_file(path)) mut p := v.new_parser(new_scanner_file(path))
p = { p| p = {
file_path: path, p|file_path:path,
file_name:path.all_after(os.path_separator), file_name:path.all_after(os.path_separator),
file_platform:path_platform, file_platform:path_platform,
file_pcguard:path_pcguard, file_pcguard:path_pcguard,
@ -188,12 +196,12 @@ fn (v mut V) new_parser(scanner &Scanner) Parser {
pref: v.pref pref: v.pref
os: v.os os: v.os
vroot: v.vroot vroot: v.vroot
local_vars: [Var{}].repeat(MaxLocalVars) local_vars: [Var{
}].repeat(MaxLocalVars)
import_table: new_import_table() import_table: new_import_table()
} }
$if js { $if js {
p.is_js = true p.is_js=true}
}
if p.pref.is_repl { if p.pref.is_repl {
p.scanner.should_print_line_on_error = false p.scanner.should_print_line_on_error = false
p.scanner.should_print_errors_in_color = false p.scanner.should_print_errors_in_color = false
@ -228,7 +236,6 @@ fn (p mut Parser) next() {
// (only when vfmt compile time flag is enabled, otherwise this function // (only when vfmt compile time flag is enabled, otherwise this function
// is not even generated) // is not even generated)
p.fnext() p.fnext()
p.prev_tok2 = p.prev_tok p.prev_tok2 = p.prev_tok
p.prev_tok = p.tok p.prev_tok = p.tok
p.scanner.prev_tok = p.tok p.scanner.prev_tok = p.tok
@ -261,18 +268,26 @@ fn (p &Parser) peek() TokenKind {
} }
return .eof return .eof
*/ */
} }
// TODO remove dups // TODO remove dups
[inline] fn (p &Parser) prev_token() Token { [inline]
fn (p &Parser) prev_token() Token {
return p.tokens[p.token_idx - 2] return p.tokens[p.token_idx - 2]
} }
[inline] fn (p &Parser) cur_tok() Token {
[inline]
fn (p &Parser) cur_tok() Token {
return p.tokens[p.token_idx - 1] return p.tokens[p.token_idx - 1]
} }
[inline] fn (p &Parser) peek_token() Token {
[inline]
fn (p &Parser) peek_token() Token {
if p.token_idx >= p.tokens.len - 2 { if p.token_idx >= p.tokens.len - 2 {
return Token{ tok:.eof } return Token{
tok: .eof
}
} }
return p.tokens[p.token_idx] return p.tokens[p.token_idx]
} }
@ -285,6 +300,7 @@ fn (p &Parser) log(s string) {
} }
println(s) println(s)
*/ */
} }
pub fn (p &Parser) save_state() ParserState { pub fn (p &Parser) save_state() ParserState {
@ -363,7 +379,8 @@ fn (p mut Parser) statements_from_text(text string, rcbr bool) {
p.next() p.next()
if rcbr { if rcbr {
p.statements() p.statements()
} else { }
else {
p.statements_no_rcbr() p.statements_no_rcbr()
} }
p.restore_state(saved_state, true, false) p.restore_state(saved_state, true, false)
@ -384,7 +401,8 @@ fn (p mut Parser) parse(pass Pass) {
p.next() p.next()
p.fspace() p.fspace()
p.mod = p.check_name() p.mod = p.check_name()
} else { }
else {
p.mod = 'main' p.mod = 'main'
} }
} }
@ -395,7 +413,6 @@ fn (p mut Parser) parse(pass Pass) {
} }
// //
p.fgenln('\n') p.fgenln('\n')
p.cgen.nogen = false p.cgen.nogen = false
if p.pref.build_mode == .build_module && p.mod != p.v.mod { if p.pref.build_mode == .build_module && p.mod != p.v.mod {
// println('skipping $p.mod (v.mod = $p.v.mod)') // println('skipping $p.mod (v.mod = $p.v.mod)')
@ -407,16 +424,11 @@ fn (p mut Parser) parse(pass Pass) {
p.can_chash = p.mod in['ui','darwin','clipboard','webview'] // TODO tmp remove p.can_chash = p.mod in['ui','darwin','clipboard','webview'] // TODO tmp remove
// Import pass - the first and the smallest pass that only analyzes imports // Import pass - the first and the smallest pass that only analyzes imports
// if we are a building module get the full module name from v.mod // if we are a building module get the full module name from v.mod
fq_mod := if p.pref.build_mode == .build_module && p.v.mod.ends_with(p.mod) { fq_mod := if p.pref.build_mode == .build_module && p.v.mod.ends_with(p.mod) {p.v.mod}
p.v.mod
}
// fully qualify the module name, eg base64 to encoding.base64 // fully qualify the module name, eg base64 to encoding.base64
else { else {p.table.qualify_module(p.mod, p.file_path)}
p.table.qualify_module(p.mod, p.file_path)
}
p.table.register_module(fq_mod) p.table.register_module(fq_mod)
p.mod = fq_mod p.mod = fq_mod
if p.pass == .imports { if p.pass == .imports {
for p.tok == .key_import && p.peek() != .key_const { for p.tok == .key_import && p.peek() != .key_const {
p.imports() p.imports()
@ -449,17 +461,24 @@ fn (p mut Parser) parse(pass Pass) {
.key_pub { .key_pub {
next := p.peek() next := p.peek()
match next { match next {
.key_fn { p.fn_decl() } .key_fn {
.key_const { p.const_decl() } p.fn_decl()
.key_struct, }
.key_union, .key_const {
.key_interface { p.struct_decl() } p.const_decl()
.key_enum { p.enum_decl(false) } }
.key_type { p.type_decl() } .key_struct,.key_union,.key_interface {
p.struct_decl()
}
.key_enum {
p.enum_decl(false)
}
.key_type {
p.type_decl()
}
else { else {
p.error('wrong pub keyword usage') p.error('wrong pub keyword usage')
} }}
}
} }
.key_fn { .key_fn {
p.fn_decl() p.fn_decl()
@ -488,13 +507,8 @@ fn (p mut Parser) parse(pass Pass) {
p.comp_time() p.comp_time()
} }
.key_global { .key_global {
if !p.pref.translated && !p.pref.is_live && if !p.pref.translated && !p.pref.is_live && !p.builtin_mod && !p.pref.building_v && p.mod != 'ui' && !os.getwd().contains('/volt') && !p.pref.enable_globals {
!p.builtin_mod && !p.pref.building_v &&
p.mod != 'ui' && !os.getwd().contains('/volt') &&
!p.pref.enable_globals
{
p.error('use `v --enable-globals ...` to enable globals') p.error('use `v --enable-globals ...` to enable globals')
// p.error('__global is only allowed in translated code') // p.error('__global is only allowed in translated code')
} }
p.next() p.next()
@ -570,8 +584,7 @@ fn (p mut Parser) parse(pass Pass) {
else { else {
p.error('unexpected token `${p.strtok()}`') p.error('unexpected token `${p.strtok()}`')
} }
} }}
}
} }
} }
@ -677,14 +690,15 @@ fn (p mut Parser) const_decl() {
p.cgen.nogen = true p.cgen.nogen = true
typ = p.expression() typ = p.expression()
p.cgen.nogen = false p.cgen.nogen = false
} else { }
else {
typ = p.get_type() typ = p.get_type()
} }
p.table.register_const(name, typ, p.mod, is_pub) p.table.register_const(name, typ, p.mod, is_pub)
p.cgen.consts << ('extern ' + p.cgen.consts << ('extern ' + p.table.cgen_name_type_pair(name, typ)) + ';'
p.table.cgen_name_type_pair(name, typ)) + ';'
continue // Don't generate C code when building a .vh file continue // Don't generate C code when building a .vh file
} else { }
else {
p.check_space(.assign) p.check_space(.assign)
typ = p.expression() typ = p.expression()
} }
@ -709,8 +723,7 @@ fn (p mut Parser) const_decl() {
// We are building module `ui`, but are parsing `gx` right now // We are building module `ui`, but are parsing `gx` right now
// (because of nogen). We need to import gx constants with `extern`. // (because of nogen). We need to import gx constants with `extern`.
// println('extern const mod=$p.mod name=$name') // println('extern const mod=$p.mod name=$name')
p.cgen.consts << ('extern ' + p.cgen.consts << ('extern ' + p.table.cgen_name_type_pair(name, typ)) + ';'
p.table.cgen_name_type_pair(name, typ)) + ';'
} }
if p.pass == .main && !p.cgen.nogen { if p.pass == .main && !p.cgen.nogen {
// TODO hack // TODO hack
@ -725,8 +738,7 @@ fn (p mut Parser) const_decl() {
continue continue
} }
if typ.starts_with('[') { if typ.starts_with('[') {
p.cgen.consts << p.table.cgen_name_type_pair(name, typ) + p.cgen.consts << p.table.cgen_name_type_pair(name, typ) + ' = $p.cgen.cur_line;'
' = $p.cgen.cur_line;'
} }
else { else {
p.cgen.consts << p.table.cgen_name_type_pair(name, typ) + ';' p.cgen.consts << p.table.cgen_name_type_pair(name, typ) + ';'
@ -762,12 +774,7 @@ fn (p mut Parser) type_decl() {
// TODO dirty C typedef hacks for DOOM // TODO dirty C typedef hacks for DOOM
// Unknown type probably means it's a struct, and it's used before the struct is defined, // Unknown type probably means it's a struct, and it's used before the struct is defined,
// so specify "struct" // so specify "struct"
_struct := if parent.cat != .array && parent.cat != .func && _struct := if parent.cat != .array && parent.cat != .func && !p.table.known_type(parent.name) {'struct'}else {''}
!p.table.known_type(parent.name) {
'struct'
} else {
''
}
p.gen_typedef('typedef $_struct $nt_pair; //type alias name="$name" parent=`$parent.name`') p.gen_typedef('typedef $_struct $nt_pair; //type alias name="$name" parent=`$parent.name`')
p.table.register_type(Type{ p.table.register_type(Type{
name: name name: name
@ -793,7 +800,8 @@ fn (p mut Parser) interface_method(field_name, receiver string) &Fn {
// No type on the same line, this method doesn't return a type, process next // No type on the same line, this method doesn't return a type, process next
if prev_tok.line_nr != cur_tok.line_nr { if prev_tok.line_nr != cur_tok.line_nr {
method.typ = 'void' method.typ = 'void'
} else { }
else {
method.typ = p.get_type() // method return type method.typ = p.get_type() // method return type
// p.fspace() // p.fspace()
p.fgen_nl() p.fgen_nl()
@ -803,11 +811,17 @@ fn (p mut Parser) interface_method(field_name, receiver string) &Fn {
fn key_to_type_cat(tok TokenKind) TypeCategory { fn key_to_type_cat(tok TokenKind) TypeCategory {
match tok { match tok {
.key_interface { return .interface_ } .key_interface {
.key_struct { return .struct_ } return .interface_
.key_union { return .union_ }
else {}
} }
.key_struct {
return .struct_
}
.key_union {
return .union_
}
else {
}}
verror('Unknown token: $tok') verror('Unknown token: $tok')
return .builtin return .builtin
} }
@ -827,7 +841,7 @@ fn (p mut Parser) check_string() string {
fn (p mut Parser) check_not_reserved() { fn (p mut Parser) check_not_reserved() {
if reserved_types[p.lit] { if reserved_types[p.lit] {
p.error('`$p.lit` can\'t be used as name') p.error("`$p.lit` can\'t be used as name")
} }
} }
@ -844,7 +858,8 @@ fn (p &Parser) strtok() string {
if p.tok == .str { if p.tok == .str {
if p.lit.contains("'") { if p.lit.contains("'") {
return '"$p.lit"' return '"$p.lit"'
} else { }
else {
return "'$p.lit'" return "'$p.lit'"
} }
} }
@ -886,15 +901,14 @@ fn (p mut Parser) check(expected TokenKind) {
p.fmt_inc() p.fmt_inc()
} }
*/ */
p.next()
p.next()
// if p.scanner.line_comment != '' { // if p.scanner.line_comment != '' {
// p.fgenln('// ! "$p.scanner.line_comment"') // p.fgenln('// ! "$p.scanner.line_comment"')
// p.scanner.line_comment = '' // p.scanner.line_comment = ''
// } // }
} }
[inline] [inline]
fn (p &Parser) first_pass() bool { fn (p &Parser) first_pass() bool {
return p.pass == .decl return p.pass == .decl
@ -927,7 +941,10 @@ fn (p mut Parser) get_type() string {
} }
// fn type // fn type
if p.tok == .key_fn { if p.tok == .key_fn {
mut f := Fn{name: '_', mod: p.mod} mut f := Fn{
name: '_',
mod: p.mod
}
p.next() p.next()
line_nr := p.scanner.line_nr line_nr := p.scanner.line_nr
p.fn_args(mut f) p.fn_args(mut f)
@ -947,6 +964,7 @@ fn (p mut Parser) get_type() string {
// Register anon fn type // Register anon fn type
fn_typ := Type{ fn_typ := Type{
name: f.typ_str() // 'fn (int, int) string' name: f.typ_str() // 'fn (int, int) string'
mod: p.mod mod: p.mod
func: f func: f
} }
@ -985,7 +1003,6 @@ fn (p mut Parser) get_type() string {
p.register_map(typ) p.register_map(typ)
return typ return typ
} }
// ptr/ref // ptr/ref
mut warn := false mut warn := false
for p.tok == .mul { for p.tok == .mul {
@ -1005,7 +1022,8 @@ fn (p mut Parser) get_type() string {
ti := p.cur_fn.dispatch_of.inst ti := p.cur_fn.dispatch_of.inst
if p.lit in ti.keys() { if p.lit in ti.keys() {
typ += ti[p.lit] typ += ti[p.lit]
} else { }
else {
typ += p.lit typ += p.lit
} }
// C.Struct import // C.Struct import
@ -1035,8 +1053,7 @@ fn (p mut Parser) get_type() string {
// "typ" not found? try "mod__typ" // "typ" not found? try "mod__typ"
if t.name == '' && !p.builtin_mod { if t.name == '' && !p.builtin_mod {
// && !p.first_pass() { // && !p.first_pass() {
if !typ.contains('array_') && p.mod != 'main' && !typ.contains('__') && if !typ.contains('array_') && p.mod != 'main' && !typ.contains('__') && !typ.starts_with('[') {
!typ.starts_with('[') {
typ = p.prepend_mod(typ) typ = p.prepend_mod(typ)
} }
t = p.table.find_type(typ) t = p.table.find_type(typ)
@ -1093,6 +1110,7 @@ fn (p mut Parser) get_type() string {
p.error('2 __ in gettype(): typ="$typ"') p.error('2 __ in gettype(): typ="$typ"')
} }
*/ */
return typ return typ
} }
@ -1123,7 +1141,6 @@ fn (p mut Parser) statements() string {
fn (p mut Parser) statements_no_rcbr() string { fn (p mut Parser) statements_no_rcbr() string {
p.open_scope() p.open_scope()
if !p.inside_if_expr { if !p.inside_if_expr {
// p.genln('') // p.genln('')
} }
@ -1147,7 +1164,6 @@ fn (p mut Parser) statements_no_rcbr() string {
// p.next() // p.next()
p.check(.rcbr) p.check(.rcbr)
// p.fmt_dec() // p.fmt_dec()
p.close_scope() p.close_scope()
return last_st_typ return last_st_typ
} }
@ -1160,12 +1176,14 @@ fn (p mut Parser) close_scope() {
mut i := p.var_idx - 1 mut i := p.var_idx - 1
for ; i >= 0; i-- { for ; i >= 0; i-- {
v := p.local_vars[i] v := p.local_vars[i]
if p.pref.autofree && (v.is_alloc || (v.is_arg && v.typ == 'string')) { // && !p.pref.is_test { if p.pref.autofree && (v.is_alloc || (v.is_arg && v.typ == 'string')) {
// && !p.pref.is_test {
p.free_var(v) p.free_var(v)
} }
// if p.fileis('mem.v') { // if p.fileis('mem.v') {
// println(v.name + ' $v.is_arg scope=$v.scope_level cur=$p.cur_fn.scope_level')} // println(v.name + ' $v.is_arg scope=$v.scope_level cur=$p.cur_fn.scope_level')}
if v.scope_level != p.cur_fn.scope_level {// && !v.is_arg { if v.scope_level != p.cur_fn.scope_level {
// && !v.is_arg {
break break
} }
} }
@ -1189,21 +1207,25 @@ fn (p mut Parser) free_var(v Var) {
mut free_fn := 'free' mut free_fn := 'free'
if v.typ.starts_with('array_') { if v.typ.starts_with('array_') {
free_fn = 'v_array_free' free_fn = 'v_array_free'
} else if v.typ == 'string' { }
else if v.typ == 'string' {
free_fn = 'v_string_free' free_fn = 'v_string_free'
// if p.fileis('str.v') { // if p.fileis('str.v') {
// println('freeing str $v.name') // println('freeing str $v.name')
// } // }
// continue // continue
} else if v.ptr || v.typ.ends_with('*') { }
else if v.ptr || v.typ.ends_with('*') {
free_fn = 'v_ptr_free' free_fn = 'v_ptr_free'
// continue // continue
} else { }
else {
return return
} }
if p.returns { if p.returns {
// Don't free a variable that's being returned // Don't free a variable that's being returned
if !v.is_returned && v.typ != 'FILE*' { //!v.is_c { if !v.is_returned && v.typ != 'FILE*' {
// !v.is_c {
// p.cgen.cur_line = '/* free */' + p.cgen.cur_line // p.cgen.cur_line = '/* free */' + p.cgen.cur_line
// p.cgen.set_placeholder(0, '/*free2*/') // p.cgen.set_placeholder(0, '/*free2*/')
prev_line := p.cgen.lines[p.cgen.lines.len - 1] prev_line := p.cgen.lines[p.cgen.lines.len - 1]
@ -1211,7 +1233,9 @@ fn (p mut Parser) free_var(v Var) {
p.cgen.lines[p.cgen.lines.len - 1] = free + '\n' + prev_line p.cgen.lines[p.cgen.lines.len - 1] = free + '\n' + prev_line
// '$free_fn ($v.name); /* :) close_scope free $v.typ */\n' + prev_line // '$free_fn ($v.name); /* :) close_scope free $v.typ */\n' + prev_line
} }
} else if p.mod != 'strings' { //&& p.mod != 'builtin' { }
else if p.mod != 'strings' {
// && p.mod != 'builtin' {
/* /*
prev_line := p.cgen.lines[p.cgen.lines.len-1] prev_line := p.cgen.lines[p.cgen.lines.len-1]
free := '$free_fn ($v.name); /* :) close_scope free $v.typ */' free := '$free_fn ($v.name); /* :) close_scope free $v.typ */'
@ -1325,7 +1349,8 @@ fn (p mut Parser) statement(add_semi bool) string {
.key_return { .key_return {
p.return_st() p.return_st()
} }
.lcbr {// {} block .lcbr {
// {} block
// Do not allow {} block to start on the same line // Do not allow {} block to start on the same line
// to avoid e.g. `foo() {` instead of `if foo() {` // to avoid e.g. `foo() {` instead of `if foo() {`
if p.prev_token().line_nr == p.scanner.line_nr { if p.prev_token().line_nr == p.scanner.line_nr {
@ -1372,8 +1397,7 @@ fn (p mut Parser) statement(add_semi bool) string {
p.genln('; ') p.genln('; ')
} }
return typ return typ
} }}
}
// ? : uses , as statement separators // ? : uses , as statement separators
if p.inside_if_expr && p.tok != .rcbr { if p.inside_if_expr && p.tok != .rcbr {
p.gen(', ') p.gen(', ')
@ -1384,7 +1408,6 @@ fn (p mut Parser) statement(add_semi bool) string {
return q return q
// p.cgen.end_statement() // p.cgen.end_statement()
} }
// is_map: are we in map assignment? (m[key] = val) if yes, dont generate '=' // is_map: are we in map assignment? (m[key] = val) if yes, dont generate '='
// this can be `user = ...` or `user.field = ...`, in both cases `v` is `user` // this can be `user = ...` or `user.field = ...`, in both cases `v` is `user`
fn (p mut Parser) assign_statement(v Var,ph int,is_map bool) { fn (p mut Parser) assign_statement(v Var,ph int,is_map bool) {
@ -1431,8 +1454,7 @@ fn ($v.name mut $v.typ) ${p.cur_fn.name}(...) {
} }
else { else {
p.gen(' ' + p.tok.str() + ' ') p.gen(' ' + p.tok.str() + ' ')
} }}
}
p.fspace() p.fspace()
p.next() p.next()
p.fspace() p.fspace()
@ -1448,16 +1470,13 @@ fn ($v.name mut $v.typ) ${p.cur_fn.name}(...) {
p.error_with_token_index('${fn_name}() $err_used_as_value', p.token_idx - 2) p.error_with_token_index('${fn_name}() $err_used_as_value', p.token_idx - 2)
} }
// Allow `num = 4` where `num` is an `?int` // Allow `num = 4` where `num` is an `?int`
if p.assigned_type.starts_with('Option_') && if p.assigned_type.starts_with('Option_') && expr_type == p.assigned_type['Option_'.len..] {
expr_type == p.assigned_type['Option_'.len..] {
expr := p.cgen.cur_line[pos..] expr := p.cgen.cur_line[pos..]
left := p.cgen.cur_line[..pos] left := p.cgen.cur_line[..pos]
typ := expr_type.replace('Option_', '') typ := expr_type.replace('Option_', '')
p.cgen.resetln(left + 'opt_ok(($typ[]){ $expr }, sizeof($typ))') p.cgen.resetln(left + 'opt_ok(($typ[]){ $expr }, sizeof($typ))')
} }
else if expr_type.starts_with('Option_') && else if expr_type.starts_with('Option_') && p.assigned_type == expr_type['Option_'.len..] && p.tok == .key_orelse {
p.assigned_type == expr_type['Option_'.len..] && p.tok == .key_orelse
{
line := p.cgen.cur_line line := p.cgen.cur_line
vname := line[..pos].replace('=', '') // TODO cgen line hack vname := line[..pos].replace('=', '') // TODO cgen line hack
if idx:=line.index('='){ if idx:=line.index('='){
@ -1514,11 +1533,9 @@ fn (p mut Parser) var_decl() {
p.check(.key_static) p.check(.key_static)
p.fspace() p.fspace()
} }
mut var_token_idxs := [p.cur_tok_index()] mut var_token_idxs := [p.cur_tok_index()]
mut var_mut := [is_mut] // add first var mut mut var_mut := [is_mut] // add first var mut
mut var_names := [p.check_name()] // add first variable mut var_names := [p.check_name()] // add first variable
p.scanner.validate_var_name(var_names[0]) p.scanner.validate_var_name(var_names[0])
mut new_vars := 0 mut new_vars := 0
if var_names[0] != '_' && !p.known_var(var_names[0]) { if var_names[0] != '_' && !p.known_var(var_names[0]) {
@ -1530,7 +1547,8 @@ fn (p mut Parser) var_decl() {
if p.tok == .key_mut { if p.tok == .key_mut {
p.check(.key_mut) p.check(.key_mut)
var_mut << true var_mut << true
} else { }
else {
var_mut << false var_mut << false
} }
var_token_idxs << p.cur_tok_index() var_token_idxs << p.cur_tok_index()
@ -1545,9 +1563,11 @@ fn (p mut Parser) var_decl() {
is_decl_assign := p.tok == .decl_assign is_decl_assign := p.tok == .decl_assign
if is_assign { if is_assign {
p.check_space(.assign) // = p.check_space(.assign) // =
} else if is_decl_assign { }
else if is_decl_assign {
p.check_space(.decl_assign) // := p.check_space(.decl_assign) // :=
} else { }
else {
p.error('expected `=` or `:=`') p.error('expected `=` or `:=`')
} }
// all vars on left of `:=` already defined (or `_`) // all vars on left of `:=` already defined (or `_`)
@ -1659,7 +1679,9 @@ fn (p mut Parser) get_struct_type(name_ string, is_c bool, is_ptr bool) string {
} }
fn (p mut Parser) get_var_type(name string,is_ptr bool,deref_nr int) string { fn (p mut Parser) get_var_type(name string,is_ptr bool,deref_nr int) string {
v := p.find_var_check_new_var(name) or { return "" } v := p.find_var_check_new_var(name) or{
return ''
}
if is_ptr { if is_ptr {
p.gen('&') p.gen('&')
} }
@ -1675,6 +1697,7 @@ fn (p mut Parser) get_var_type(name string, is_ptr bool, deref_nr int) string {
p.mark_arg_moved(v) p.mark_arg_moved(v)
} }
*/ */
mut typ := p.var_expr(v) mut typ := p.var_expr(v)
// *var // *var
if deref_nr > 0 { if deref_nr > 0 {
@ -1691,7 +1714,6 @@ fn (p mut Parser) get_var_type(name string, is_ptr bool, deref_nr int) string {
typ = typ.replace_once('ptr', '') // TODO typ = typ.replace_once('ptr', '') // TODO
typ = typ.replace_once('*', '') // TODO typ = typ.replace_once('*', '') // TODO
} }
} }
// &var // &var
else if is_ptr { else if is_ptr {
@ -1708,10 +1730,13 @@ fn (p mut Parser) get_var_type(name string, is_ptr bool, deref_nr int) string {
} }
fn (p mut Parser) get_const_type(name string,is_ptr bool) string { fn (p mut Parser) get_const_type(name string,is_ptr bool) string {
c := p.table.find_const(name) or { return "" } c := p.table.find_const(name) or{
return ''
}
if is_ptr && !c.is_global { if is_ptr && !c.is_global {
p.error('cannot take the address of constant `$c.name`') p.error('cannot take the address of constant `$c.name`')
} else if is_ptr && c.is_global { }
else if is_ptr && c.is_global {
// c.ptr = true // c.ptr = true
p.gen('& /*const*/ ') p.gen('& /*const*/ ')
} }
@ -1739,8 +1764,7 @@ fn (p mut Parser) get_c_func_type(name string) string {
// without declaring `foo`? // without declaring `foo`?
// Do not allow it. // Do not allow it.
if !name.starts_with('gl') && !name.starts_with('glad') { if !name.starts_with('gl') && !name.starts_with('glad') {
p.error('undefined C function `$f.name`\n' + p.error('undefined C function `$f.name`\n' + 'define it with `fn C.${name}([args]) [return_type]`')
'define it with `fn C.${name}([args]) [return_type]`')
} }
return 'void*' return 'void*'
} }
@ -1758,7 +1782,8 @@ fn (p mut Parser) undefined_error(name string, orig_name string) {
// If orig_name is a mod, then printing undefined: `mod` tells us nothing // If orig_name is a mod, then printing undefined: `mod` tells us nothing
if p.table.known_mod(orig_name) || p.import_table.known_alias(orig_name) { if p.table.known_mod(orig_name) || p.import_table.known_alias(orig_name) {
p.error('undefined: `$name_dotted` (in module `$orig_name`)') p.error('undefined: `$name_dotted` (in module `$orig_name`)')
} else if orig_name in reserved_type_param_names { }
else if orig_name in reserved_type_param_names {
p.error('the letter `$orig_name` is reserved for type parameters') p.error('the letter `$orig_name` is reserved for type parameters')
} }
p.error('undefined: `$orig_name`') p.error('undefined: `$orig_name`')
@ -1800,14 +1825,14 @@ fn (p mut Parser) var_expr(v Var) string {
p.next() p.next()
return p.select_query(fn_ph) return p.select_query(fn_ph)
} }
if typ == 'pg__DB' && !p.fileis('pg.v') && p.peek() == .name if typ == 'pg__DB' && !p.fileis('pg.v') && p.peek() == .name {
{
name := p.tokens[p.token_idx].lit name := p.tokens[p.token_idx].lit
if !name.contains('exec') && !name.starts_with('q_') { if !name.contains('exec') && !name.starts_with('q_') {
p.next() p.next()
if name == 'insert' { if name == 'insert' {
p.insert_query(fn_ph) p.insert_query(fn_ph)
} else if name == 'update' { }
else if name == 'update' {
p.update_query(fn_ph) p.update_query(fn_ph)
} }
return 'void' return 'void'
@ -1918,7 +1943,8 @@ fn (p mut Parser) dot(str_typ_ string, method_ph int) string {
p.error_with_token_index('type `$typ.name` has no field or method `$field_name`', fname_tidx) p.error_with_token_index('type `$typ.name` has no field or method `$field_name`', fname_tidx)
} }
mut dot := '.' mut dot := '.'
if str_typ.ends_with('*') || str_typ == 'FT_Face' { // TODO fix C ptr typedefs if str_typ.ends_with('*') || str_typ == 'FT_Face' {
// TODO fix C ptr typedefs
dot = dot_ptr dot = dot_ptr
} }
// field // field
@ -1934,13 +1960,10 @@ fn (p mut Parser) dot(str_typ_ string, method_ph int) string {
} }
// Is the next token `=`, `+=` etc? (Are we modifying the field?) // Is the next token `=`, `+=` etc? (Are we modifying the field?)
next := p.peek() next := p.peek()
modifying := next.is_assign() || next == .inc || next == .dec || modifying := next.is_assign() || next == .inc || next == .dec || (field.typ.starts_with('array_') && next == .left_shift)
(field.typ.starts_with('array_') && next == .left_shift) if !p.builtin_mod && !p.pref.translated && modifying && p.has_immutable_field {
if !p.builtin_mod && !p.pref.translated && modifying &&
p.has_immutable_field {
f := p.first_immutable_field f := p.first_immutable_field
p.error_with_token_index('cannot modify immutable field `$f.name` (type `$f.parent_fn`)\n' + p.error_with_token_index('cannot modify immutable field `$f.name` (type `$f.parent_fn`)\n' + 'declare the field with `mut:`
'declare the field with `mut:`
struct $f.parent_fn { struct $f.parent_fn {
mut: mut:
$f.name $f.typ $f.name $f.typ
@ -1951,15 +1974,13 @@ struct $f.parent_fn {
if field.access_mod == .private && !p.builtin_mod && !p.pref.translated && p.mod != typ.mod && !p.is_vgen { if field.access_mod == .private && !p.builtin_mod && !p.pref.translated && p.mod != typ.mod && !p.is_vgen {
// println('$typ.name :: $field.name ') // println('$typ.name :: $field.name ')
// println(field.access_mod) // println(field.access_mod)
p.error_with_token_index('cannot refer to unexported field `$struct_field` (type `$typ.name`)\n' + p.error_with_token_index('cannot refer to unexported field `$struct_field` (type `$typ.name`)\n' + 'declare the field with `pub:`
'declare the field with `pub:`
struct $typ.name { struct $typ.name {
pub: pub:
$struct_field $field.typ $struct_field $field.typ
} }
', fname_tidx) ', fname_tidx)
} }
if p.base_type(field.typ).starts_with('fn ') && p.peek() == .lpar { if p.base_type(field.typ).starts_with('fn ') && p.peek() == .lpar {
tmp_typ := p.table.find_type(field.typ) tmp_typ := p.table.find_type(field.typ)
mut f := tmp_typ.func mut f := tmp_typ.func
@ -1970,7 +1991,6 @@ struct $typ.name {
p.gen(')') p.gen(')')
return f.typ return f.typ
} }
p.gen(dot + struct_field) p.gen(dot + struct_field)
p.next() p.next()
return field.typ return field.typ
@ -1983,6 +2003,9 @@ struct $typ.name {
p.fn_call(mut method, method_ph, '', str_typ) p.fn_call(mut method, method_ph, '', str_typ)
// optional method call `a.method() or {}`, no return assignment // optional method call `a.method() or {}`, no return assignment
is_or_else := p.tok == .key_orelse is_or_else := p.tok == .key_orelse
if is_or_else {
p.fspace()
}
if p.tok == .question { if p.tok == .question {
// `files := os.ls('.')?` // `files := os.ls('.')?`
return p.gen_handle_question_suffix(method, method_ph) return p.gen_handle_question_suffix(method, method_ph)
@ -1990,8 +2013,7 @@ struct $typ.name {
else if !p.is_var_decl && is_or_else { else if !p.is_var_decl && is_or_else {
method.typ = p.gen_handle_option_or_else(method.typ, '', method_ph) method.typ = p.gen_handle_option_or_else(method.typ, '', method_ph)
} }
else if !p.is_var_decl && !is_or_else && !p.inside_return_expr && else if !p.is_var_decl && !is_or_else && !p.inside_return_expr && method.typ.starts_with('Option_') {
method.typ.starts_with('Option_') {
opt_type := method.typ[7..] opt_type := method.typ[7..]
p.error('unhandled option type: `?$opt_type`') p.error('unhandled option type: `?$opt_type`')
} }
@ -2024,13 +2046,21 @@ enum IndexType {
} }
fn get_index_type(typ string) IndexType { fn get_index_type(typ string) IndexType {
if typ.starts_with('map_') { return .map } if typ.starts_with('map_') {
if typ == 'string' { return .str } return .map
if typ.starts_with('array_') || typ == 'array' { return .array } }
if typ == 'string' {
return .str
}
if typ.starts_with('array_') || typ == 'array' {
return .array
}
if typ == 'byte*' || typ == 'byteptr' || typ.contains('*') { if typ == 'byte*' || typ == 'byteptr' || typ.contains('*') {
return .ptr return .ptr
} }
if typ[0] == `[` { return .fixed_array } if typ[0] == `[` {
return .fixed_array
}
return .noindex return .noindex
} }
@ -2071,7 +2101,9 @@ fn (p mut Parser) index_expr(typ_ string, fn_ph int) string {
p.gen(', ') p.gen(', ')
} }
} }
if is_variadic_arg { typ = typ[5..] } if is_variadic_arg {
typ = typ[5..]
}
if is_fixed_arr { if is_fixed_arr {
// `[10]int` => `int`, `[10][3]int` => `[3]int` // `[10]int` => `int`, `[10][3]int` => `[3]int`
if typ.contains('][') { if typ.contains('][') {
@ -2131,9 +2163,11 @@ fn (p mut Parser) index_expr(typ_ string, fn_ph int) string {
if p.tok == .dotdot { if p.tok == .dotdot {
if is_arr { if is_arr {
typ = 'array_' + typ typ = 'array_' + typ
} else if is_str { }
else if is_str {
typ = 'string' typ = 'string'
} else { }
else {
p.error('slicing is supported by arrays and strings only') p.error('slicing is supported by arrays and strings only')
} }
is_slice = true is_slice = true
@ -2334,11 +2368,10 @@ fn (p mut Parser) assoc() string {
} }
fn (p mut Parser) char_expr() { fn (p mut Parser) char_expr() {
p.gen('\'$p.lit\'') p.gen("\'$p.lit\'")
p.next() p.next()
} }
fn format_str(_str string) string { fn format_str(_str string) string {
// TODO don't call replace 3 times for every string, do this in scanner.v // TODO don't call replace 3 times for every string, do this in scanner.v
mut str := _str.replace('"', '\\"') mut str := _str.replace('"', '\\"')
@ -2384,8 +2417,7 @@ fn (p mut Parser) map_init() string {
} }
p.fgen_nl() p.fgen_nl()
} }
p.gen('new_map_init($i, sizeof($val_type), ' + p.gen('new_map_init($i, sizeof($val_type), ' + '(string[$i]){ $keys_gen }, ($val_type [$i]){ $vals_gen } )')
'(string[$i]){ $keys_gen }, ($val_type [$i]){ $vals_gen } )')
typ := 'map_$val_type' typ := 'map_$val_type'
p.register_map(typ) p.register_map(typ)
return typ return typ
@ -2407,8 +2439,7 @@ fn (p mut Parser) map_init() string {
if p.tok == .lcbr { if p.tok == .lcbr {
p.check(.lcbr) p.check(.lcbr)
p.check(.rcbr) p.check(.rcbr)
println('warning: $p.file_name:$p.scanner.line_nr ' + println('warning: $p.file_name:$p.scanner.line_nr ' + 'initializaing maps no longer requires `{}`')
'initializaing maps no longer requires `{}`')
} }
return typ return typ
} }
@ -2431,10 +2462,12 @@ fn (p mut Parser) array_init() string {
// p.error('unknown const `$p.lit`') // p.error('unknown const `$p.lit`')
exit(1) exit(1)
} }
if c.typ == 'int' && p.peek() == .rsbr { //&& !p.inside_const { if c.typ == 'int' && p.peek() == .rsbr {
// && !p.inside_const {
is_integer = true is_integer = true
is_const_len = true is_const_len = true
} else { }
else {
p.error('bad fixed size array const `$p.lit`') p.error('bad fixed size array const `$p.lit`')
} }
} }
@ -2449,8 +2482,7 @@ fn (p mut Parser) array_init() string {
if i == 0 { if i == 0 {
typ = val_typ typ = val_typ
// fixed width array initialization? (`arr := [20]byte`) // fixed width array initialization? (`arr := [20]byte`)
if is_integer && p.tok == .rsbr && p.peek() == .name && if is_integer && p.tok == .rsbr && p.peek() == .name && p.cur_tok().line_nr == p.peek_token().line_nr {
p.cur_tok().line_nr == p.peek_token().line_nr {
// there is no space between `[10]` and `byte` // there is no space between `[10]` and `byte`
// if p.cur_tok().col + p.peek_token().lit.len == p.peek_token().col { // if p.cur_tok().col + p.peek_token().lit.len == p.peek_token().col {
if p.cur_tok().pos + p.peek_token().lit.len == p.peek_token().pos { if p.cur_tok().pos + p.peek_token().lit.len == p.peek_token().pos {
@ -2466,7 +2498,8 @@ fn (p mut Parser) array_init() string {
return '[${mod_gen_name(p.mod)}__$lit]$array_elem_typ' return '[${mod_gen_name(p.mod)}__$lit]$array_elem_typ'
} }
return '[$lit]$array_elem_typ' return '[$lit]$array_elem_typ'
} else { }
else {
p.check(.rsbr) p.check(.rsbr)
typ = p.get_type() typ = p.get_type()
p.error('no space allowed between [$lit] and $typ') p.error('no space allowed between [$lit] and $typ')
@ -2505,14 +2538,15 @@ fn (p mut Parser) array_init() string {
if p.tok != .name && p.tok != .mul && p.tok != .lsbr && i == 0 && !exp_array { if p.tok != .name && p.tok != .mul && p.tok != .lsbr && i == 0 && !exp_array {
p.error('specify array type: `[]typ` instead of `[]`') p.error('specify array type: `[]typ` instead of `[]`')
} }
if i == 0 && (p.tok == .name || p.tok == .mul) && if i == 0 && (p.tok == .name || p.tok == .mul) && p.tokens[p.token_idx - 2].line_nr == p.tokens[p.token_idx - 1].line_nr {
p.tokens[p.token_idx-2].line_nr == p.tokens[p.token_idx-1].line_nr { // TODO // TODO
// vals.len == 0 { // vals.len == 0 {
if exp_array { if exp_array {
p.error('no need to specify the full array type here, use `[]` instead of `[]${p.expected_type[6..]}`') p.error('no need to specify the full array type here, use `[]` instead of `[]${p.expected_type[6..]}`')
} }
typ = p.get_type().replace('*', '_ptr') typ = p.get_type().replace('*', '_ptr')
} else if exp_array && i == 0 { }
else if exp_array && i == 0 {
// allow `known_array = []` // allow `known_array = []`
typ = p.expected_type[6..] typ = p.expected_type[6..]
} }
@ -2521,7 +2555,6 @@ fn (p mut Parser) array_init() string {
if no_alloc { if no_alloc {
p.next() p.next()
} }
// [1,2,3]!! => [3]int{1,2,3} // [1,2,3]!! => [3]int{1,2,3}
is_fixed_size := p.tok == .not is_fixed_size := p.tok == .not
if is_fixed_size { if is_fixed_size {
@ -2542,7 +2575,6 @@ fn (p mut Parser) array_init() string {
// if ptr { // if ptr {
// typ += '_ptr" // typ += '_ptr"
// } // }
real := typ.replace('_ptr', '*') real := typ.replace('_ptr', '*')
p.gen_array_init(real, no_alloc, new_arr_ph, i) p.gen_array_init(real, no_alloc, new_arr_ph, i)
typ = 'array_$typ' typ = 'array_$typ'
@ -2552,7 +2584,6 @@ fn (p mut Parser) array_init() string {
// `f32(3)` // `f32(3)`
// tok is `f32` or `)` if `(*int)(ptr)` // tok is `f32` or `)` if `(*int)(ptr)`
fn (p mut Parser) get_tmp() string { fn (p mut Parser) get_tmp() string {
p.tmp_cnt++ p.tmp_cnt++
return 'tmp$p.tmp_cnt' return 'tmp$p.tmp_cnt'
@ -2563,7 +2594,6 @@ fn (p mut Parser) get_tmp_counter() int {
return p.tmp_cnt return p.tmp_cnt
} }
fn (p mut Parser) assert_statement() { fn (p mut Parser) assert_statement() {
if p.first_pass() { if p.first_pass() {
return return
@ -2577,8 +2607,7 @@ fn (p mut Parser) assert_statement() {
// TODO print "expected: got" for failed tests // TODO print "expected: got" for failed tests
filename := cescaped_path(p.file_path) filename := cescaped_path(p.file_path)
cfname := p.cur_fn.name.replace('main__', '') cfname := p.cur_fn.name.replace('main__', '')
sourceline := p.scanner.line( nline - 1 ).replace('"', '\'') sourceline := p.scanner.line(nline - 1).replace('"', "\'")
if !p.pref.is_test { if !p.pref.is_test {
// an assert used in a normal v program. no fancy formatting // an assert used in a normal v program. no fancy formatting
p.genln(';\n p.genln(';\n
@ -2595,7 +2624,6 @@ if (!$tmp) {
') ')
return return
} }
p.genln(';\n p.genln(';\n
if (!$tmp) { if (!$tmp) {
g_test_fails++; g_test_fails++;
@ -2663,8 +2691,7 @@ fn (p mut Parser) return_st() {
// Automatically wrap an object inside an option if the function // Automatically wrap an object inside an option if the function
// returns an option: // returns an option:
// `return val` => `return opt_ok(val)` // `return val` => `return opt_ok(val)`
if p.cur_fn.typ.ends_with(expr_type) && !is_none && if p.cur_fn.typ.ends_with(expr_type) && !is_none && p.cur_fn.typ.starts_with('Option_') {
p.cur_fn.typ.starts_with('Option_') {
tmp := p.get_tmp() tmp := p.get_tmp()
ret := p.cgen.cur_line[ph..] ret := p.cgen.cur_line[ph..]
typ := expr_type.replace('Option_', '') typ := expr_type.replace('Option_', '')
@ -2674,15 +2701,16 @@ fn (p mut Parser) return_st() {
} }
else { else {
ret := p.cgen.cur_line[ph..] ret := p.cgen.cur_line[ph..]
if deferred_text == '' || expr_type == 'void*' { if deferred_text == '' || expr_type == 'void*' {
// no defer{} necessary? // no defer{} necessary?
if expr_type == '${p.cur_fn.typ}*' { if expr_type == '${p.cur_fn.typ}*' {
p.cgen.resetln('return *$ret') p.cgen.resetln('return *$ret')
} else { }
else {
p.cgen.resetln('return $ret') p.cgen.resetln('return $ret')
} }
} else { }
else {
tmp := p.get_tmp() tmp := p.get_tmp()
p.cgen.resetln('$expr_type $tmp = $ret;\n') p.cgen.resetln('$expr_type $tmp = $ret;\n')
p.genln(deferred_text) p.genln(deferred_text)
@ -2696,7 +2724,6 @@ fn (p mut Parser) return_st() {
if p.tok == .name || p.tok == .number || p.tok == .str { if p.tok == .name || p.tok == .number || p.tok == .str {
p.error_with_token_index('function `$p.cur_fn.name` should not return a value', p.cur_fn.fn_name_token_idx) p.error_with_token_index('function `$p.cur_fn.name` should not return a value', p.cur_fn.fn_name_token_idx)
} }
p.genln(deferred_text) p.genln(deferred_text)
if p.cur_fn.name == 'main' { if p.cur_fn.name == 'main' {
p.gen('return 0') p.gen('return 0')
@ -2841,7 +2868,8 @@ fn (p mut Parser) attribute() {
// [if vfmt] // [if vfmt]
p.next() p.next()
p.attr = 'if ' + p.check_name() p.attr = 'if ' + p.check_name()
} else { }
else {
p.attr = p.check_name() p.attr = p.check_name()
} }
attr_token_idx := p.cur_tok_index() attr_token_idx := p.cur_tok_index()
@ -2872,27 +2900,24 @@ fn (p mut Parser) attribute() {
fn (p mut Parser) defer_st() { fn (p mut Parser) defer_st() {
p.check(.key_defer) p.check(.key_defer)
p.check(.lcbr) p.check(.lcbr)
pos := p.cgen.lines.len pos := p.cgen.lines.len
// Save everything inside the defer block to `defer_text`. // Save everything inside the defer block to `defer_text`.
// It will be inserted before every `return` // It will be inserted before every `return`
// Emily: TODO: all variables that are used in this defer statement need to be evaluated when the block // Emily: TODO: all variables that are used in this defer statement need to be evaluated when the block
// is defined otherwise they could change over the course of the function // is defined otherwise they could change over the course of the function
// (make temps out of them) // (make temps out of them)
p.genln('{') p.genln('{')
p.statements() p.statements()
p.cur_fn.defer_text.last() = p.cgen.lines[pos..].join('\n') + p.cur_fn.defer_text.last() p.cur_fn.defer_text.last() = p.cgen.lines[pos..].join('\n') + p.cur_fn.defer_text.last()
// Rollback p.cgen.lines // Rollback p.cgen.lines
p.cgen.lines = p.cgen.lines[..pos] p.cgen.lines = p.cgen.lines[..pos]
p.cgen.resetln('') p.cgen.resetln('')
} }
fn (p mut Parser) check_and_register_used_imported_type(typ_name string) { fn (p mut Parser) check_and_register_used_imported_type(typ_name string) {
us_idx := typ_name.index('__') or { return } us_idx := typ_name.index('__') or{
return
}
arg_mod := typ_name[..us_idx] arg_mod := typ_name[..us_idx]
if p.import_table.known_alias(arg_mod) { if p.import_table.known_alias(arg_mod) {
p.import_table.register_used_import(arg_mod) p.import_table.register_used_import(arg_mod)
@ -2911,7 +2936,9 @@ fn (p mut Parser) check_unused_imports() {
output += '\n * $mod_alias' output += '\n * $mod_alias'
} }
} }
if output == '' { return } if output == '' {
return
}
// the imports are usually at the start of the file // the imports are usually at the start of the file
p.production_error_with_token_index('the following imports were never used: $output', 0) p.production_error_with_token_index('the following imports were never used: $output', 0)
} }
@ -2921,8 +2948,7 @@ fn (p &Parser) is_expr_fn_call(start_tok_idx int) (bool, string) {
mut is_fn_call := p.tokens[start_tok_idx].tok == .lpar mut is_fn_call := p.tokens[start_tok_idx].tok == .lpar
if !is_fn_call { if !is_fn_call {
mut i := start_tok_idx mut i := start_tok_idx
for (p.tokens[i].tok == .dot || p.tokens[i].tok == .name) && for (p.tokens[i].tok == .dot || p.tokens[i].tok == .name) && p.tokens[i].lit != '_' && i < p.tokens.len {
p.tokens[i].lit != '_' && i < p.tokens.len {
expr += p.tokens[i].str() expr += p.tokens[i].str()
i++ i++
} }

View File

@ -10,10 +10,12 @@ import os
[if vfmt] [if vfmt]
fn (scanner mut Scanner) fgen(s_ string) { fn (scanner mut Scanner) fgen(s_ string) {
mut s := s_ mut s := s_
if s != ' ' {
//s = s.trim_space()
}
if scanner.fmt_line_empty { if scanner.fmt_line_empty {
s = strings.repeat(`\t`, scanner.fmt_indent) + s.trim_left(' ') s = strings.repeat(`\t`, scanner.fmt_indent) + s.trim_left(' ')
} }
scanner.fmt_lines << s scanner.fmt_lines << s
//scanner.fmt_out << s //scanner.fmt_out << s
//scanner.fmt_out.write(s) //scanner.fmt_out.write(s)
@ -22,7 +24,7 @@ fn (scanner mut Scanner) fgen(s_ string) {
[if vfmt] [if vfmt]
fn (scanner mut Scanner) fgenln(s_ string) { fn (scanner mut Scanner) fgenln(s_ string) {
mut s := s_ mut s := s_//.trim_space()
if scanner.fmt_line_empty && scanner.fmt_indent > 0 { if scanner.fmt_line_empty && scanner.fmt_indent > 0 {
s = strings.repeat(`\t`, scanner.fmt_indent) + s s = strings.repeat(`\t`, scanner.fmt_indent) + s
} }
@ -227,7 +229,8 @@ fn (p &Parser) gen_fmt() {
} }
//s := p.scanner.fmt_out.str().replace('\n\n\n', '\n').trim_space() //s := p.scanner.fmt_out.str().replace('\n\n\n', '\n').trim_space()
//s := p.scanner.fmt_out.str().trim_space() //s := p.scanner.fmt_out.str().trim_space()
s := p.scanner.fmt_lines.join('').trim_space() s := p.scanner.fmt_lines.join('').trim_space().replace('\n\n\n\n', '\n\n')
.replace(' \n', '\n')
if s == '' { if s == '' {
return return
} }