diff --git a/vlib/builtin/float.v b/vlib/builtin/float.v index 964929d39b..d7165a7429 100644 --- a/vlib/builtin/float.v +++ b/vlib/builtin/float.v @@ -1,51 +1,54 @@ // 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 builtin #include - pub fn (d f64) str() string { - buf := malloc(sizeof(double) * 5 + 1)// TODO + buf := malloc(sizeof(double) * 5 + 1) // TODO C.sprintf(charptr(buf), '%f', d) return tos(buf, vstrlen(buf)) } pub fn (d f32) str() string { - buf := malloc(sizeof(double) * 5 + 1)// TODO + buf := malloc(sizeof(double) * 5 + 1) // TODO C.sprintf(charptr(buf), '%f', d) return tos(buf, vstrlen(buf)) } - // return a string of the input f64 in scientific notation with digit_num digits displayed -pub fn (x f64) strsci(digit_num int) string{ - buf := malloc(digit_num*2+2)// TODO - conf_str := '%0.'+digit_num.str()+'e' +pub fn (x f64) strsci(digit_num int) string { + buf := malloc(digit_num * 2 + 2) // TODO + conf_str := '%0.' + digit_num.str() + 'e' C.sprintf(charptr(buf), charptr(conf_str.str), x) tmpstr := tos(buf, vstrlen(buf)) return tmpstr } -// return a long string of the input f64, max +// return a long string of the input f64, max pub fn (x f64) strlong() string { - buf := malloc(18+32)// TODO - C.sprintf(charptr(buf),"%0.30lf",x) + buf := malloc(18 + 32) // TODO + C.sprintf(charptr(buf), '%0.30lf', x) tmpstr := tos(buf, vstrlen(buf)) return tmpstr } -fn f32_abs(a f32) f32 { return if a < 0 { -a } else { a } } -fn f64_abs(a f64) f64 { return if a < 0 { -a } else { a } } +fn f32_abs(a f32) f32 { + return if a < 0 { -a } else { a } +} + +fn f64_abs(a f64) f64 { + return if a < 0 { -a } else { a } +} // compare floats using C epsilon // == pub fn (a f64) eq(b f64) bool { - return f64_abs(a - b) <= C.DBL_EPSILON + return f64_abs(a - b) <= C.DBL_EPSILON } + pub fn (a f32) eq(b f32) bool { - return f32_abs(a - b) <= C.FLT_EPSILON + return f32_abs(a - b) <= C.FLT_EPSILON } pub fn (a f64) eqbit(b f64) bool { @@ -60,12 +63,15 @@ pub fn (a f32) eqbit(b f32) bool { fn (a f64) ne(b f64) bool { return !a.eq(b) } + fn (a f32) ne(b f32) bool { return !a.eq(b) } + pub fn (a f64) nebit(b f64) bool { return C.DEFAULT_NOT_EQUAL(a, b) } + pub fn (a f32) nebit(b f32) bool { return C.DEFAULT_NOT_EQUAL(a, b) } @@ -74,12 +80,15 @@ pub fn (a f32) nebit(b f32) bool { fn (a f64) lt(b f64) bool { return a.ne(b) && a.ltbit(b) } + fn (a f32) lt(b f32) bool { return a.ne(b) && a.ltbit(b) } + fn (a f64) ltbit(b f64) bool { return C.DEFAULT_LT(a, b) } + fn (a f32) ltbit(b f32) bool { return C.DEFAULT_LT(a, b) } @@ -88,12 +97,15 @@ fn (a f32) ltbit(b f32) bool { fn (a f64) le(b f64) bool { return !a.gt(b) } + fn (a f32) le(b f32) bool { return !a.gt(b) } + fn (a f64) lebit(b f64) bool { return C.DEFAULT_LE(a, b) } + fn (a f32) lebit(b f32) bool { return C.DEFAULT_LE(a, b) } @@ -102,12 +114,15 @@ fn (a f32) lebit(b f32) bool { fn (a f64) gt(b f64) bool { return a.ne(b) && a.gtbit(b) } + fn (a f32) gt(b f32) bool { return a.ne(b) && a.gtbit(b) } + fn (a f64) gtbit(b f64) bool { return C.DEFAULT_GT(a, b) } + fn (a f32) gtbit(b f32) bool { return C.DEFAULT_GT(a, b) } @@ -116,16 +131,15 @@ fn (a f32) gtbit(b f32) bool { fn (a f64) ge(b f64) bool { return !a.lt(b) } + fn (a f32) ge(b f32) bool { return !a.lt(b) } + fn (a f64) gebit(b f64) bool { return C.DEFAULT_GE(a, b) } + fn (a f32) gebit(b f32) bool { return C.DEFAULT_GE(a, b) } - - - - diff --git a/vlib/compiler/comptime.v b/vlib/compiler/comptime.v index 6d6572840f..452f221d1c 100644 --- a/vlib/compiler/comptime.v +++ b/vlib/compiler/comptime.v @@ -199,6 +199,7 @@ fn (p mut Parser) comp_time() { fn (p mut Parser) chash() { hash := p.lit.trim_space() // println('chsh() file=$p.file hash="$hash"') + p.fgen_nl() p.next() if hash.starts_with('flag ') { if p.first_pass() { diff --git a/vlib/compiler/expression.v b/vlib/compiler/expression.v index c2eb9756b8..a338a858a6 100644 --- a/vlib/compiler/expression.v +++ b/vlib/compiler/expression.v @@ -1,7 +1,6 @@ // 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 fn (p mut Parser) bool_expression() string { @@ -12,11 +11,15 @@ fn (p mut Parser) bool_expression() string { for p.tok == .and || p.tok == .logical_or { if p.tok == .and { got_and = true - if got_or { p.error(and_or_error) } + if got_or { + p.error(and_or_error) + } } if p.tok == .logical_or { got_or = true - if got_and { p.error(and_or_error) } + if got_and { + p.error(and_or_error) + } } if p.is_sql { if p.tok == .and { @@ -25,7 +28,8 @@ fn (p mut Parser) bool_expression() string { else if p.tok == .logical_or { p.gen(' or ') } - } else { + } + else { p.gen(' ${p.tok.str()} ') } p.check_space(p.tok) @@ -47,12 +51,10 @@ fn (p mut Parser) bterm() string { ph := p.cgen.add_placeholder() mut typ := p.expression() p.expected_type = typ - is_str := typ=='string' && !p.is_sql - is_ustr := typ=='ustring' + is_str := typ == 'string' && !p.is_sql + is_ustr := typ == 'ustring' base := p.base_type(typ) - is_float := base[0] == `f` && (base in ['f64', 'f32']) && - !(p.cur_fn.name in ['f64_abs', 'f32_abs']) && - p.cur_fn.name != 'eq' + is_float := base[0] == `f` && (base in ['f64', 'f32']) && !(p.cur_fn.name in ['f64_abs', 'f32_abs']) && p.cur_fn.name != 'eq' is_array := typ.starts_with('array_') expr_type := base tok := p.tok @@ -61,14 +63,14 @@ fn (p mut Parser) bterm() string { p.error('no = ') } */ + if tok in [.eq, .gt, .lt, .le, .ge, .ne] { - //TODO: remove when array comparing is supported + // TODO: remove when array comparing is supported if is_array { p.error('array comparison is not supported yet') } - p.fspace() - //p.fgen(' ${p.tok.str()} ') + // p.fgen(' ${p.tok.str()} ') if (is_float || is_str || is_ustr) && !p.is_js { p.gen(',') } @@ -88,47 +90,85 @@ fn (p mut Parser) bterm() string { p.check_types(p.expression(), typ) sql_param := p.cgen.cut() p.sql_params << sql_param - p.sql_types << typ - //println('*** sql type: $typ | param: $sql_param') - } else { + p.sql_types << typ + // println('*** sql type: $typ | param: $sql_param') + } + else { p.check_types(p.expression(), typ) } typ = 'bool' - if is_str && !p.is_js { //&& !p.is_sql { + if is_str && !p.is_js { + // && !p.is_sql { p.gen(')') match tok { - .eq { p.cgen.set_placeholder(ph, 'string_eq(') } - .ne { p.cgen.set_placeholder(ph, 'string_ne(') } - .le { p.cgen.set_placeholder(ph, 'string_le(') } - .ge { p.cgen.set_placeholder(ph, 'string_ge(') } - .gt { p.cgen.set_placeholder(ph, 'string_gt(') } - .lt { p.cgen.set_placeholder(ph, 'string_lt(') } - else { } - } + .eq { + p.cgen.set_placeholder(ph, 'string_eq(') + } + .ne { + p.cgen.set_placeholder(ph, 'string_ne(') + } + .le { + p.cgen.set_placeholder(ph, 'string_le(') + } + .ge { + p.cgen.set_placeholder(ph, 'string_ge(') + } + .gt { + p.cgen.set_placeholder(ph, 'string_gt(') + } + .lt { + p.cgen.set_placeholder(ph, 'string_lt(') + } + else { + }} } if is_ustr { p.gen(')') match tok { - .eq { p.cgen.set_placeholder(ph, 'ustring_eq(') } - .ne { p.cgen.set_placeholder(ph, 'ustring_ne(') } - .le { p.cgen.set_placeholder(ph, 'ustring_le(') } - .ge { p.cgen.set_placeholder(ph, 'ustring_ge(') } - .gt { p.cgen.set_placeholder(ph, 'ustring_gt(') } - .lt { p.cgen.set_placeholder(ph, 'ustring_lt(') } - else { } - } + .eq { + p.cgen.set_placeholder(ph, 'ustring_eq(') + } + .ne { + p.cgen.set_placeholder(ph, 'ustring_ne(') + } + .le { + p.cgen.set_placeholder(ph, 'ustring_le(') + } + .ge { + p.cgen.set_placeholder(ph, 'ustring_ge(') + } + .gt { + p.cgen.set_placeholder(ph, 'ustring_gt(') + } + .lt { + p.cgen.set_placeholder(ph, 'ustring_lt(') + } + else { + }} } if is_float && p.cur_fn.name != 'f32_abs' && p.cur_fn.name != 'f64_abs' { p.gen(')') match tok { - .eq { p.cgen.set_placeholder(ph, '${expr_type}_eq(') } - .ne { p.cgen.set_placeholder(ph, '${expr_type}_ne(') } - .le { p.cgen.set_placeholder(ph, '${expr_type}_le(') } - .ge { p.cgen.set_placeholder(ph, '${expr_type}_ge(') } - .gt { p.cgen.set_placeholder(ph, '${expr_type}_gt(') } - .lt { p.cgen.set_placeholder(ph, '${expr_type}_lt(') } - else { } - } + .eq { + p.cgen.set_placeholder(ph, '${expr_type}_eq(') + } + .ne { + p.cgen.set_placeholder(ph, '${expr_type}_ne(') + } + .le { + p.cgen.set_placeholder(ph, '${expr_type}_le(') + } + .ge { + p.cgen.set_placeholder(ph, '${expr_type}_ge(') + } + .gt { + p.cgen.set_placeholder(ph, '${expr_type}_gt(') + } + .lt { + p.cgen.set_placeholder(ph, '${expr_type}_lt(') + } + else { + }} } } return typ @@ -142,19 +182,20 @@ fn (p mut Parser) name_expr() string { // amp ptr := p.tok == .amp deref := p.tok == .mul - mut mul_nr := 0 - mut deref_nr := 0 - for { - if p.tok == .amp { - mul_nr++ - }else if p.tok == .mul { - deref_nr++ - }else { - break - } - p.next() - } - + mut mul_nr := 0 + mut deref_nr := 0 + for { + if p.tok == .amp { + mul_nr++ + } + else if p.tok == .mul { + deref_nr++ + } + else { + break + } + p.next() + } if p.tok == .lpar { p.gen('*'.repeat(deref_nr)) p.gen('(') @@ -162,7 +203,7 @@ fn (p mut Parser) name_expr() string { mut temp_type := p.bool_expression() p.gen(')') p.check(.rpar) - for _ in 0..deref_nr { + for _ in 0 .. deref_nr { temp_type = temp_type.replace_once('*', '') } return temp_type @@ -194,15 +235,15 @@ fn (p mut Parser) name_expr() string { p.check(.dot) name = p.lit // C struct initialization - if p.peek() == .lcbr && p.expected_type == '' { // not an expression + if p.peek() == .lcbr && p.expected_type == '' { + // not an expression if !p.table.known_type(name) { - p.error('unknown C type `$name`, ' + - 'define it with `struct C.$name { ... }`') + p.error('unknown C type `$name`, ' + 'define it with `struct C.$name { ... }`') } return p.get_struct_type(name, true, ptr) } if ptr && p.peek() == .lpar { - peek2 := p.tokens[p.token_idx+1] + peek2 := p.tokens[p.token_idx + 1] // `&C.Foo(0)` cast (replacing old `&C.Foo{!}`) if peek2.tok == .number && peek2.lit == '0' { p.cgen.insert_before('struct /*C.Foo(0)*/ ') @@ -232,8 +273,9 @@ fn (p mut Parser) name_expr() string { p.check_enum_member_access() // println("found enum value: $p.expected_type") return p.expected_type - } else { - p.error("unknown enum: `$p.expected_type`") + } + else { + p.error('unknown enum: `$p.expected_type`') } } // Variable, checked before modules, so that module shadowing is allowed: @@ -242,9 +284,7 @@ fn (p mut Parser) name_expr() string { return p.get_var_type(name, ptr, deref_nr) } // Module? - if p.peek() == .dot && (name == p.mod || - p.import_table.known_alias(name)) && !is_c - { + if p.peek() == .dot && (name == p.mod || p.import_table.known_alias(name)) && !is_c { mut mod := name // must be aliased module if name != p.mod && p.import_table.known_alias(name) { @@ -258,9 +298,7 @@ fn (p mut Parser) name_expr() string { } // Unknown name, try prepending the module name to it // TODO perf - else if !p.table.known_type(name) && - !p.table.known_fn(name) && !p.table.known_const(name) && !is_c - { + else if !p.table.known_type(name) && !p.table.known_fn(name) && !p.table.known_const(name) && !is_c { name = p.prepend_mod(name) } // re-check @@ -271,18 +309,18 @@ fn (p mut Parser) name_expr() string { // known type? int(4.5) or Color.green (enum) if p.table.known_type(name) { // cast expression: float(5), byte(0), (*int)(ptr) etc - //if !is_c && ( p.peek() == .lpar || (deref && p.peek() == .rpar) ) { + // if !is_c && ( p.peek() == .lpar || (deref && p.peek() == .rpar) ) { if p.peek() == .lpar || (deref && p.peek() == .rpar) { if deref { - name += '*'.repeat(deref_nr ) + name += '*'.repeat(deref_nr) } else if ptr { name += '*'.repeat(mul_nr) } - //p.gen('(') + // p.gen('(') mut typ := name p.cast(typ) - //p.gen(')') + // p.gen(')') for p.tok == .dot { typ = p.dot(typ, ph) } @@ -306,7 +344,7 @@ fn (p mut Parser) name_expr() string { p.warn('`${enum_type.name}.$val` is unnecessary, use `.$val`') } // println('enum val $val') - p.gen(mod_gen_name(enum_type.mod) + '__' + enum_type.name + '_' + val)// `color = main__Color_green` + p.gen(mod_gen_name(enum_type.mod) + '__' + enum_type.name + '_' + val) // `color = main__Color_green` p.next() return enum_type.name } @@ -315,7 +353,6 @@ fn (p mut Parser) name_expr() string { return p.get_struct_type(name, false, ptr) } } - // Constant if p.table.known_const(name) { return p.get_const_type(name, ptr) @@ -330,28 +367,29 @@ fn (p mut Parser) name_expr() string { } // exhaused all options type,enum,const,mod,var,fn etc // so show undefined error (also checks typos) - p.undefined_error(name, orig_name) return '' // panics + p.undefined_error(name, orig_name) + return '' // panics } // no () after func, so func is an argument, just gen its name // TODO verify this and handle errors peek := p.peek() if peek != .lpar && peek != .lt { // Register anon fn type - fn_typ := Type { - name: f.typ_str()// 'fn (int, int) string' + fn_typ := Type{ + name: f.typ_str() // 'fn (int, int) string' + mod: p.mod func: f } p.table.register_type(fn_typ) p.gen(p.table.fn_gen_name(f)) p.next() - return f.typ_str() //'void*' + return f.typ_str() // 'void*' } // TODO bring back if f.typ == 'void' && !p.inside_if_expr { // p.error('`$f.name` used as value') } - fn_call_ph := p.cgen.add_placeholder() // println('call to fn $f.name of type $f.typ') // TODO replace the following dirty hacks (needs ptr access to fn table) @@ -365,7 +403,6 @@ fn (p mut Parser) name_expr() string { // println(' from $f2.name(${f2.str_args(p.table)}) $f2.typ : $f2.type_inst') } f = new_f - // optional function call `function() or {}`, no return assignment is_or_else := p.tok == .key_orelse if p.tok == .question { @@ -375,12 +412,10 @@ fn (p mut Parser) name_expr() string { else if !p.is_var_decl && is_or_else { f.typ = p.gen_handle_option_or_else(f.typ, '', fn_call_ph) } - else if !p.is_var_decl && !is_or_else && !p.inside_return_expr && - f.typ.starts_with('Option_') { - opt_type := f.typ[7..] - p.error('unhandled option type: `?$opt_type`') - } - + else if !p.is_var_decl && !is_or_else && !p.inside_return_expr && f.typ.starts_with('Option_') { + opt_type := f.typ[7..] + p.error('unhandled option type: `?$opt_type`') + } // dot after a function call: `get_user().age` if p.tok == .dot { mut typ := '' @@ -390,8 +425,7 @@ fn (p mut Parser) name_expr() string { } return typ } - //p.log('end of name_expr') - + // p.log('end of name_expr') if f.typ.ends_with('*') { p.is_alloc = true } @@ -401,14 +435,14 @@ fn (p mut Parser) name_expr() string { // returns resulting type fn (p mut Parser) expression() string { p.is_const_literal = true - //if p.scanner.file_path.contains('test_test') { - //println('expression() pass=$p.pass tok=') - //p.print_tok() - //} + // if p.scanner.file_path.contains('test_test') { + // println('expression() pass=$p.pass tok=') + // p.print_tok() + // } ph := p.cgen.add_placeholder() typ := p.indot_expr() - is_str := typ=='string' - is_ustr := typ=='ustring' + is_str := typ == 'string' + is_ustr := typ == 'ustring' // `a << b` ==> `array_push(&a, b)` if p.tok == .left_shift { if typ.contains('array_') { @@ -416,17 +450,16 @@ fn (p mut Parser) expression() string { // a << 7 => int tmp = 7; array_push(&a, &tmp); // _PUSH(&a, expression(), tmp, string) tmp := p.get_tmp() - tmp_typ := typ[6..].replace('_ptr','*')// skip "array_" + tmp_typ := typ[6..].replace('_ptr', '*') // skip "array_" p.check_space(.left_shift) // Get the value we are pushing p.gen(', (') // Immutable? Can we push? if !p.expr_var.is_mut && !p.pref.translated { - p.error('`$p.expr_var.name` is immutable (can\'t <<)') + p.error("`$p.expr_var.name` is immutable (can\'t <<)") } if p.expr_var.is_arg && p.expr_var.typ.starts_with('array_') { - p.error("for now it's not possible to append an element to "+ - 'a mutable array argument `$p.expr_var.name`') + p.error("for now it's not possible to append an element to " + 'a mutable array argument `$p.expr_var.name`') } if !p.expr_var.is_changed { p.mark_var_changed(p.expr_var) @@ -443,7 +476,7 @@ fn (p mut Parser) expression() string { return 'void' } else { - if !is_integer_type(typ) { + if !is_integer_type(typ) { t := p.table.find_type(typ) if t.cat != .enum_ { p.error('cannot use shift operator on non-integer type `$typ`') @@ -456,7 +489,7 @@ fn (p mut Parser) expression() string { } } if p.tok == .righ_shift { - if !is_integer_type(typ) { + if !is_integer_type(typ) { t := p.table.find_type(typ) if t.cat != .enum_ { p.error('cannot use shift operator on non-integer type `$typ`') @@ -473,7 +506,7 @@ fn (p mut Parser) expression() string { if typ == 'bool' { p.error('operator ${p.tok.str()} not defined on bool ') } - is_num := typ.contains('*') || is_number_type(typ) || is_number_type(p.base_type(typ)) + is_num := typ.contains('*') || is_number_type(typ) || is_number_type(p.base_type(typ)) p.check_space(p.tok) if is_str && tok_op == .plus && !p.is_js { p.is_alloc = true @@ -490,15 +523,16 @@ fn (p mut Parser) expression() string { // Msvc errors on void* pointer arithmatic // ... So cast to byte* and then do the add p.cgen.set_placeholder(ph, '(byte*)') - }else if typ.contains('*') { - p.cgen.set_placeholder(ph, '($typ)') - } + } + else if typ.contains('*') { + p.cgen.set_placeholder(ph, '($typ)') + } p.gen(tok_op.str()) } // Vec + Vec else { if p.pref.translated { - p.gen(tok_op.str() + ' /*doom hack*/')// TODO hack to fix DOOM's angle_t + p.gen(tok_op.str() + ' /*doom hack*/') // TODO hack to fix DOOM's angle_t } else { p.gen(',') @@ -510,10 +544,10 @@ fn (p mut Parser) expression() string { expr_type := p.term() open := tok_op == .amp && p.tok in [.eq, .ne] // force precedence `(a & b) == c` //false if tok_op in [.pipe, .amp, .xor] { - if !(is_integer_type(expr_type) && is_integer_type(typ)) { + if !(is_integer_type(expr_type) && is_integer_type(typ)) { p.error('operator ${tok_op.str()} is defined only on integer types') } - //open = true + // open = true } if open { p.cgen.set_placeholder(ph, '(') @@ -528,15 +562,19 @@ fn (p mut Parser) expression() string { // Make sure operators are used with correct types if !p.pref.translated && !is_str && !is_ustr && !is_num { T := p.table.find_type(typ) - if tok_op == .plus { p.handle_operator('+', typ, 'op_plus', ph, T) } - else if tok_op == .minus { p.handle_operator('-', typ, 'op_minus', ph, T) } + if tok_op == .plus { + p.handle_operator('+', typ, 'op_plus', ph, T) + } + else if tok_op == .minus { + p.handle_operator('-', typ, 'op_minus', ph, T) + } } } return typ } fn (p mut Parser) handle_operator(op string, typ string, cpostfix string, ph int, T &Type) { - if T.has_method( op ) { + if T.has_method(op) { p.cgen.set_placeholder(ph, '${typ}_${cpostfix}(') p.gen(')') } @@ -547,14 +585,14 @@ fn (p mut Parser) handle_operator(op string, typ string, cpostfix string, ph int fn (p mut Parser) term() string { line_nr := p.scanner.line_nr - //if p.fileis('fn_test') { - //println('\nterm() $line_nr') - //} + // if p.fileis('fn_test') { + // println('\nterm() $line_nr') + // } ph := p.cgen.add_placeholder() typ := p.unary() - //if p.fileis('fn_test') { - //println('2: $line_nr') - //} + // if p.fileis('fn_test') { + // println('2: $line_nr') + // } // `*` on a newline? Can't be multiplication, only dereference if p.tok == .mul && line_nr != p.scanner.line_nr { return typ @@ -566,7 +604,7 @@ fn (p mut Parser) term() string { is_mod := tok == .mod p.fspace() p.next() - p.gen(tok.str())// + ' /*op2*/ ') + p.gen(tok.str()) // + ' /*op2*/ ') oph := p.cgen.add_placeholder() p.fspace() if (is_div || is_mod) && p.tok == .number && p.lit == '0' { @@ -580,23 +618,29 @@ fn (p mut Parser) term() string { p.check_types(expr_type, typ) T := p.table.find_type(typ) // NB: oph is a char index just after the OP - before_oph := p.cgen.cur_line[..oph-1] + before_oph := p.cgen.cur_line[..oph - 1] after_oph := p.cgen.cur_line[oph..] p.cgen.cur_line = before_oph + ',' + after_oph match tok { - .mul { p.handle_operator('*', typ, 'op_mul', ph, T) } - .div { p.handle_operator('/', typ, 'op_div', ph, T) } - .mod { p.handle_operator('%', typ, 'op_mod', ph, T) } - else {} - } + .mul { + p.handle_operator('*', typ, 'op_mul', ph, T) + } + .div { + p.handle_operator('/', typ, 'op_div', ph, T) + } + .mod { + p.handle_operator('%', typ, 'op_mod', ph, T) + } + else { + }} continue } - if is_mod { if !(is_integer_type(expr_type) && is_integer_type(typ)) { p.error('operator `mod` requires integer types') } - } else { + } + else { p.check_types(expr_type, typ) } } @@ -607,24 +651,23 @@ fn (p mut Parser) unary() string { mut typ := '' tok := p.tok match tok { - .not { - p.gen('!') - p.check(.not) - // typ should be bool type - typ = p.indot_expr() - if typ != 'bool' { - p.error('operator ! requires bool type, not `$typ`') + .not { + p.gen('!') + p.check(.not) + // typ should be bool type + typ = p.indot_expr() + if typ != 'bool' { + p.error('operator ! requires bool type, not `$typ`') + } } - } - .bit_not { - p.gen('~') - p.check(.bit_not) - typ = p.bool_expression() - } - else { - typ = p.factor() - } - } + .bit_not { + p.gen('~') + p.check(.bit_not) + typ = p.bool_expression() + } + else { + typ = p.factor() + }} return typ } @@ -632,72 +675,72 @@ fn (p mut Parser) factor() string { mut typ := '' tok := p.tok match tok { - .key_none { - if !p.expected_type.starts_with('Option_') { - p.error('need "$p.expected_type" got none') - } - p.gen('opt_none()') - p.check(.key_none) - return p.expected_type - } - .number { - typ = 'int' - // Check if float (`1.0`, `1e+3`) but not if is hexa - if (p.lit.contains('.') || (p.lit.contains('e') || p.lit.contains('E'))) && - !(p.lit[0] == `0` && (p.lit[1] == `x` || p.lit[1] == `X`)) { - typ = 'f32' - // typ = 'f64' // TODO - } else { - v_u64 := p.lit.u64() - if u64(u32(v_u64)) < v_u64 { - typ = 'u64' + .key_none { + if !p.expected_type.starts_with('Option_') { + p.error('need "$p.expected_type" got none') } + p.gen('opt_none()') + p.check(.key_none) + return p.expected_type } - if p.expected_type != '' && !is_valid_int_const(p.lit, p.expected_type) { - p.error('constant `$p.lit` overflows `$p.expected_type`') - } - p.gen(p.lit) - } - .minus { - p.gen('-') - p.next() - return p.factor() - // Variable - } - .key_sizeof { - p.gen('sizeof(') - p.fgen('sizeof(') - p.next() - p.check(.lpar) - mut sizeof_typ := p.get_type() - p.check(.rpar) - p.gen('$sizeof_typ)') - p.fgen('$sizeof_typ)') - return 'int' - } - .amp, .dot, .mul { - // (dot is for enum vals: `.green`) - return p.name_expr() - } - .name { - // map[string]int - if p.lit == 'map' && p.peek() == .lsbr { - return p.map_init() - } - if p.lit == 'json' && p.peek() == .dot { - if !('json' in p.table.imports) { - p.error('undefined: `json`, use `import json`') + .number { + typ = 'int' + // Check if float (`1.0`, `1e+3`) but not if is hexa + if (p.lit.contains('.') || (p.lit.contains('e') || p.lit.contains('E'))) && !(p.lit[0] == `0` && (p.lit[1] == `x` || p.lit[1] == `X`)) { + typ = 'f32' + // typ = 'f64' // TODO } - p.import_table.register_used_import('json') - return p.js_decode() + else { + v_u64 := p.lit.u64() + if u64(u32(v_u64)) < v_u64 { + typ = 'u64' + } + } + if p.expected_type != '' && !is_valid_int_const(p.lit, p.expected_type) { + p.error('constant `$p.lit` overflows `$p.expected_type`') + } + p.gen(p.lit) } - //if p.fileis('orm_test') { - //println('ORM name: $p.lit') - //} - typ = p.name_expr() - return typ - } - /* + .minus { + p.gen('-') + p.next() + return p.factor() + // Variable + } + .key_sizeof { + p.gen('sizeof(') + // p.fgen('sizeof(') + p.next() + p.check(.lpar) + mut sizeof_typ := p.get_type() + p.check(.rpar) + p.gen('$sizeof_typ)') + // p.fgen('$sizeof_typ)') + return 'int' + } + .amp,.dot,.mul { + // (dot is for enum vals: `.green`) + return p.name_expr() + } + .name { + // map[string]int + if p.lit == 'map' && p.peek() == .lsbr { + return p.map_init() + } + if p.lit == 'json' && p.peek() == .dot { + if !('json' in p.table.imports) { + p.error('undefined: `json`, use `import json`') + } + p.import_table.register_used_import('json') + return p.js_decode() + } + // if p.fileis('orm_test') { + // println('ORM name: $p.lit') + // } + typ = p.name_expr() + return typ + } + /* .key_default { p.next() p.next() @@ -710,71 +753,71 @@ fn (p mut Parser) factor() string { return 'T' } */ - .lpar { - //p.gen('(/*lpar*/') - p.gen('(') - p.check(.lpar) - typ = p.bool_expression() - // Hack. If this `)` referes to a ptr cast `(*int__)__`, it was already checked - // TODO: fix parser so that it doesn't think it's a par expression when it sees `(` in - // __(__*int)( - if !p.ptr_cast { - p.check(.rpar) + + .lpar { + // p.gen('(/*lpar*/') + p.gen('(') + p.check(.lpar) + typ = p.bool_expression() + // Hack. If this `)` referes to a ptr cast `(*int__)__`, it was already checked + // TODO: fix parser so that it doesn't think it's a par expression when it sees `(` in + // __(__*int)( + if !p.ptr_cast { + p.check(.rpar) + } + p.ptr_cast = false + p.gen(')') + return typ } - p.ptr_cast = false - p.gen(')') - return typ - } - .chartoken { - p.char_expr() - typ = 'byte' - return typ - } - .str { - p.string_expr() - typ = 'string' - return typ - } - .key_false { - typ = 'bool' - p.gen('0') - } - .key_true { - typ = 'bool' - p.gen('1') - } - .lsbr { - // `[1,2,3]` or `[]` or `[20]byte` - // TODO have to return because arrayInit does next() - // everything should do next() - return p.array_init() - } - .lcbr { - // `m := { 'one': 1 }` - if p.peek() == .str { - return p.map_init() + .chartoken { + p.char_expr() + typ = 'byte' + return typ } - // { user | name :'new name' } - return p.assoc() - } - .key_if { - typ = p.if_statement(true, 0) - return typ - } - .key_match { - typ = p.match_statement(true) - return typ - } - else { - if p.pref.is_verbose || p.pref.is_debug { - next := p.peek() - println('prev=${p.prev_tok.str()}') - println('next=${next.str()}') + .str { + p.string_expr() + typ = 'string' + return typ } - p.error('unexpected token: `${p.tok.str()}`') - } - } - p.next()// TODO everything should next() + .key_false { + typ = 'bool' + p.gen('0') + } + .key_true { + typ = 'bool' + p.gen('1') + } + .lsbr { + // `[1,2,3]` or `[]` or `[20]byte` + // TODO have to return because arrayInit does next() + // everything should do next() + return p.array_init() + } + .lcbr { + // `m := { 'one': 1 }` + if p.peek() == .str { + return p.map_init() + } + // { user | name :'new name' } + return p.assoc() + } + .key_if { + typ = p.if_statement(true, 0) + return typ + } + .key_match { + typ = p.match_statement(true) + return typ + } + else { + if p.pref.is_verbose || p.pref.is_debug { + next := p.peek() + println('prev=${p.prev_tok.str()}') + println('next=${next.str()}') + } + p.error('unexpected token: `${p.tok.str()}`') + }} + p.next() // TODO everything should next() return typ } diff --git a/vlib/compiler/if_match.v b/vlib/compiler/if_match.v index 61f2eb7ff8..3c41ee1134 100644 --- a/vlib/compiler/if_match.v +++ b/vlib/compiler/if_match.v @@ -277,6 +277,9 @@ fn (p mut Parser) if_statement(is_expr bool, elif_depth int) string { } p.fspace() p.check(.lcbr) + if p.inside_if_expr { + p.fspace() + } mut typ := '' // if { if hack if p.tok == .key_if && p.inside_if_expr { @@ -289,7 +292,9 @@ fn (p mut Parser) if_statement(is_expr bool, elif_depth int) string { if_returns := p.returns p.returns = false if p.tok == .key_else { - if !p.inside_if_expr { + if p.inside_if_expr { + p.fspace() + } else { p.fgen_nl() } p.check(.key_else) @@ -318,6 +323,9 @@ fn (p mut Parser) if_statement(is_expr bool, elif_depth int) string { p.genln(' else { ') } p.check(.lcbr) + if is_expr { + p.fspace() + } // statements() returns the type of the last statement first_typ := typ typ = p.statements() diff --git a/vlib/compiler/parser.v b/vlib/compiler/parser.v index 5ab0ca15bf..5e6fcc9222 100644 --- a/vlib/compiler/parser.v +++ b/vlib/compiler/parser.v @@ -7,6 +7,7 @@ import ( os strings compiler.x64 + //time ) struct Parser { @@ -212,7 +213,9 @@ fn (v mut V) new_parser(scanner &Scanner) Parser { return p } +// __global scan_time i64 fn (p mut Parser) scan_tokens() { + //t := time.ticks() for { res := p.scanner.scan() p.tokens << Token{ @@ -225,6 +228,8 @@ fn (p mut Parser) scan_tokens() { break } } + // scan_time += time.ticks() - t + // println('scan tokens $p.file_name $scan_time ') } fn (p mut Parser) set_current_fn(f Fn) { @@ -866,6 +871,9 @@ fn (p &Parser) strtok() string { return "'$p.lit'" } } + if p.tok == .hash { + return '#' + p.lit + } res := p.tok.str() if res == '' { n := int(p.tok) @@ -967,7 +975,7 @@ fn (p mut Parser) get_type() string { // Register anon fn type fn_typ := Type{ name: f.typ_str() // 'fn (int, int) string' - + mod: p.mod func: f } @@ -1165,6 +1173,9 @@ fn (p mut Parser) statements_no_rcbr() string { } } // p.next() + if p.inside_if_expr { + p.fspace() + } p.check(.rcbr) // p.fmt_dec() p.close_scope() @@ -1821,12 +1832,12 @@ fn (p mut Parser) var_expr(v Var) string { if p.tok == .lsbr { typ = p.index_expr(typ, fn_ph) if p.base_type(typ).starts_with('fn ') && p.tok == .lpar { - T := p.table.find_type(p.base_type(typ)) - p.gen('(') - p.fn_call_args(mut T.func) - p.gen(')') - typ = T.func.typ - } + T := p.table.find_type(p.base_type(typ)) + p.gen('(') + p.fn_call_args(mut T.func) + p.gen(')') + typ = T.func.typ + } } // a.b.c().d chain // mut dc := 0 diff --git a/vlib/compiler/string_expression.v b/vlib/compiler/string_expression.v index 26bf1141bb..369204e201 100644 --- a/vlib/compiler/string_expression.v +++ b/vlib/compiler/string_expression.v @@ -1,7 +1,6 @@ // 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 fn (p mut Parser) string_expr() { @@ -13,12 +12,13 @@ fn (p mut Parser) string_expr() { str := p.lit // No ${}, just return a simple string if p.peek() != .str_dollar || is_raw { - f := if is_raw { cescaped_path(str) } else { format_str(str) } + f := if is_raw {cescaped_path(str)}else {format_str(str)} // `C.puts('hi')` => `puts("hi");` /* Calling a C function sometimes requires a call to a string method C.fun('ssss'.to_wide()) => fun(string_to_wide(tos3("ssss"))) */ + if (p.calling_c && p.peek() != .dot) || is_cstr || (p.pref.translated && p.mod == 'main') { p.gen('"$f"') } @@ -40,12 +40,12 @@ fn (p mut Parser) string_expr() { p.is_alloc = true // $ interpolation means there's allocation mut args := '"' mut format := '"' - mut complex_inter := false // for vfmt + mut complex_inter := false // for vfmt for p.tok == .str { // Add the string between %d's p.lit = p.lit.replace('%', '%%') format += format_str(p.lit) - p.next()// skip $ + p.next() // skip $ if p.tok != .str_dollar { continue } @@ -58,7 +58,7 @@ fn (p mut Parser) string_expr() { complex_inter = true } // Get bool expr inside a temp var - typ, val_ := p.tmp_expr() + typ,val_ := p.tmp_expr() val := val_.trim_space() args += ', $val' if typ == 'string' { @@ -70,7 +70,7 @@ fn (p mut Parser) string_expr() { args += '.len, ${val}.s.str' } if typ == 'bool' { - //args += '.len, ${val}.str' + // args += '.len, ${val}.str' } // Custom format? ${t.hour:02d} custom := p.tok == .colon @@ -81,16 +81,17 @@ fn (p mut Parser) string_expr() { cformat += '.' p.next() } - if p.tok == .minus { // support for left aligned formatting + if p.tok == .minus { + // support for left aligned formatting cformat += '-' p.next() } - cformat += p.lit// 02 + cformat += p.lit // 02 p.next() fspec := p.lit // f cformat += fspec if fspec == 's' { - //println('custom str F=$cformat | format_specifier: "$fspec" | typ: $typ ') + // 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}') } @@ -120,12 +121,12 @@ fn (p mut Parser) string_expr() { } format += f } - //println('interpolation format is: |${format}| args are: |${args}| ') + // println('interpolation format is: |${format}| args are: |${args}| ') } if complex_inter { p.fgen('}') } - //p.fgen('\'') + // p.fgen('\'') // println("hello %d", num) optimization. if p.cgen.nogen { return @@ -151,4 +152,3 @@ fn (p mut Parser) string_expr() { p.gen('_STR($format$args)') } } - diff --git a/vlib/compiler/vfmt.v b/vlib/compiler/vfmt.v index 569376ebfb..1c5187d6b6 100644 --- a/vlib/compiler/vfmt.v +++ b/vlib/compiler/vfmt.v @@ -243,7 +243,7 @@ fn (p &Parser) gen_fmt() { if s == '' { return } - if !p.file_name.contains('parser.v') {return} + //if !p.file_name.contains('float.v') {return} path := os.tmpdir() + '/' + p.file_name println('generating ${path}') mut out := os.create(path) or { diff --git a/vlib/strings/similarity.v b/vlib/strings/similarity.v index 4b4a337ea0..9e19b506c7 100644 --- a/vlib/strings/similarity.v +++ b/vlib/strings/similarity.v @@ -1,20 +1,21 @@ module strings -#-js +//#-js // use levenshtein distance algorithm to calculate // the distance between between two strings (lower is closer) pub fn levenshtein_distance(a, b string) int { - mut f := [0].repeat(b.len+1) + mut f := [0].repeat(b.len + 1) for ca in a { mut j := 1 mut fj1 := f[0] f[0]++ for cb in b { - mut mn := if f[j]+1 <= f[j-1]+1 { f[j]+1 } else { f[j-1]+1 } + mut mn := if f[j] + 1 <= f[j - 1] + 1 { f[j] + 1 } else { f[j - 1] + 1 } if cb != ca { - mn = if mn <= fj1+1 { mn } else { fj1+1 } - } else { + mn = if mn <= fj1 + 1 { mn } else { fj1 + 1 } + } + else { mn = if mn <= fj1 { mn } else { fj1 } } fj1 = f[j] @@ -22,7 +23,7 @@ pub fn levenshtein_distance(a, b string) int { j++ } } - return f[f.len-1] + return f[f.len - 1] } // use levenshtein distance algorithm to calculate @@ -30,28 +31,33 @@ pub fn levenshtein_distance(a, b string) int { pub fn levenshtein_distance_percentage(a, b string) f32 { d := levenshtein_distance(a, b) l := if a.len >= b.len { a.len } else { b.len } - return (1.00 - f32(d)/f32(l)) * 100.00 + return (1.00 - f32(d) / f32(l)) * 100.00 } // implementation of Sørensen–Dice coefficient. // find the similarity between two strings. // returns coefficient between 0.0 (not similar) and 1.0 (exact match). pub fn dice_coefficient(s1, s2 string) f32 { - if s1.len == 0 || s2.len == 0 { return 0.0 } - if s1 == s2 { return 1.0 } - if s1.len < 2 || s2.len < 2 { return 0.0 } + if s1.len == 0 || s2.len == 0 { + return 0.0 + } + if s1 == s2 { + return 1.0 + } + if s1.len < 2 || s2.len < 2 { + return 0.0 + } a := if s1.len > s2.len { s1 } else { s2 } b := if a == s1 { s2 } else { s1 } mut first_bigrams := map[string]int - for i := 0; i < a.len-1; i++ { - bigram := a[i..i+2] - q := if bigram in first_bigrams { - first_bigrams[bigram]+1 } else { 1 } + for i := 0; i < a.len - 1; i++ { + bigram := a[i..i + 2] + q := if bigram in first_bigrams { first_bigrams[bigram] + 1 } else { 1 } first_bigrams[bigram] = q } mut intersection_size := 0 - for i := 0; i < b.len-1; i++ { - bigram := b[i..i+2] + for i := 0; i < b.len - 1; i++ { + bigram := b[i..i + 2] count := if bigram in first_bigrams { first_bigrams[bigram] } else { 0 } if count > 0 { first_bigrams[bigram] = count - 1