1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

run vfmt on more files

This commit is contained in:
Alexander Medvednikov 2019-12-18 21:56:30 +03:00
parent 1cef83aea4
commit df2f98e276
8 changed files with 403 additions and 320 deletions

View File

@ -1,51 +1,54 @@
// 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 builtin module builtin
#include <float.h> #include <float.h>
pub fn (d f64) str() string { 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) C.sprintf(charptr(buf), '%f', d)
return tos(buf, vstrlen(buf)) return tos(buf, vstrlen(buf))
} }
pub fn (d f32) str() string { 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) C.sprintf(charptr(buf), '%f', d)
return tos(buf, vstrlen(buf)) return tos(buf, vstrlen(buf))
} }
// return a string of the input f64 in scientific notation with digit_num digits displayed // return a string of the input f64 in scientific notation with digit_num digits displayed
pub fn (x f64) strsci(digit_num int) string{ pub fn (x f64) strsci(digit_num int) string {
buf := malloc(digit_num*2+2)// TODO buf := malloc(digit_num * 2 + 2) // TODO
conf_str := '%0.'+digit_num.str()+'e' conf_str := '%0.' + digit_num.str() + 'e'
C.sprintf(charptr(buf), charptr(conf_str.str), x) C.sprintf(charptr(buf), charptr(conf_str.str), x)
tmpstr := tos(buf, vstrlen(buf)) tmpstr := tos(buf, vstrlen(buf))
return tmpstr 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 { pub fn (x f64) strlong() string {
buf := malloc(18+32)// TODO buf := malloc(18 + 32) // TODO
C.sprintf(charptr(buf),"%0.30lf",x) C.sprintf(charptr(buf), '%0.30lf', x)
tmpstr := tos(buf, vstrlen(buf)) tmpstr := tos(buf, vstrlen(buf))
return tmpstr return tmpstr
} }
fn f32_abs(a f32) f32 { return if a < 0 { -a } else { a } } fn f32_abs(a f32) f32 {
fn f64_abs(a f64) f64 { return if a < 0 { -a } else { a } } 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 // compare floats using C epsilon
// == // ==
pub fn (a f64) eq(b f64) bool { 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 { 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 { 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 { fn (a f64) ne(b f64) bool {
return !a.eq(b) return !a.eq(b)
} }
fn (a f32) ne(b f32) bool { fn (a f32) ne(b f32) bool {
return !a.eq(b) return !a.eq(b)
} }
pub fn (a f64) nebit(b f64) bool { pub fn (a f64) nebit(b f64) bool {
return C.DEFAULT_NOT_EQUAL(a, b) return C.DEFAULT_NOT_EQUAL(a, b)
} }
pub fn (a f32) nebit(b f32) bool { pub fn (a f32) nebit(b f32) bool {
return C.DEFAULT_NOT_EQUAL(a, b) 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 { fn (a f64) lt(b f64) bool {
return a.ne(b) && a.ltbit(b) return a.ne(b) && a.ltbit(b)
} }
fn (a f32) lt(b f32) bool { fn (a f32) lt(b f32) bool {
return a.ne(b) && a.ltbit(b) return a.ne(b) && a.ltbit(b)
} }
fn (a f64) ltbit(b f64) bool { fn (a f64) ltbit(b f64) bool {
return C.DEFAULT_LT(a, b) return C.DEFAULT_LT(a, b)
} }
fn (a f32) ltbit(b f32) bool { fn (a f32) ltbit(b f32) bool {
return C.DEFAULT_LT(a, b) return C.DEFAULT_LT(a, b)
} }
@ -88,12 +97,15 @@ fn (a f32) ltbit(b f32) bool {
fn (a f64) le(b f64) bool { fn (a f64) le(b f64) bool {
return !a.gt(b) return !a.gt(b)
} }
fn (a f32) le(b f32) bool { fn (a f32) le(b f32) bool {
return !a.gt(b) return !a.gt(b)
} }
fn (a f64) lebit(b f64) bool { fn (a f64) lebit(b f64) bool {
return C.DEFAULT_LE(a, b) return C.DEFAULT_LE(a, b)
} }
fn (a f32) lebit(b f32) bool { fn (a f32) lebit(b f32) bool {
return C.DEFAULT_LE(a, b) return C.DEFAULT_LE(a, b)
} }
@ -102,12 +114,15 @@ fn (a f32) lebit(b f32) bool {
fn (a f64) gt(b f64) bool { fn (a f64) gt(b f64) bool {
return a.ne(b) && a.gtbit(b) return a.ne(b) && a.gtbit(b)
} }
fn (a f32) gt(b f32) bool { fn (a f32) gt(b f32) bool {
return a.ne(b) && a.gtbit(b) return a.ne(b) && a.gtbit(b)
} }
fn (a f64) gtbit(b f64) bool { fn (a f64) gtbit(b f64) bool {
return C.DEFAULT_GT(a, b) return C.DEFAULT_GT(a, b)
} }
fn (a f32) gtbit(b f32) bool { fn (a f32) gtbit(b f32) bool {
return C.DEFAULT_GT(a, b) return C.DEFAULT_GT(a, b)
} }
@ -116,16 +131,15 @@ fn (a f32) gtbit(b f32) bool {
fn (a f64) ge(b f64) bool { fn (a f64) ge(b f64) bool {
return !a.lt(b) return !a.lt(b)
} }
fn (a f32) ge(b f32) bool { fn (a f32) ge(b f32) bool {
return !a.lt(b) return !a.lt(b)
} }
fn (a f64) gebit(b f64) bool { fn (a f64) gebit(b f64) bool {
return C.DEFAULT_GE(a, b) return C.DEFAULT_GE(a, b)
} }
fn (a f32) gebit(b f32) bool { fn (a f32) gebit(b f32) bool {
return C.DEFAULT_GE(a, b) return C.DEFAULT_GE(a, b)
} }

View File

@ -199,6 +199,7 @@ fn (p mut Parser) comp_time() {
fn (p mut Parser) chash() { fn (p mut Parser) chash() {
hash := p.lit.trim_space() hash := p.lit.trim_space()
// println('chsh() file=$p.file hash="$hash"') // println('chsh() file=$p.file hash="$hash"')
p.fgen_nl()
p.next() p.next()
if hash.starts_with('flag ') { if hash.starts_with('flag ') {
if p.first_pass() { if p.first_pass() {

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
fn (p mut Parser) bool_expression() string { 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 { for p.tok == .and || p.tok == .logical_or {
if p.tok == .and { if p.tok == .and {
got_and = true got_and = true
if got_or { p.error(and_or_error) } if got_or {
p.error(and_or_error)
}
} }
if p.tok == .logical_or { if p.tok == .logical_or {
got_or = true 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.is_sql {
if p.tok == .and { if p.tok == .and {
@ -25,7 +28,8 @@ fn (p mut Parser) bool_expression() string {
else if p.tok == .logical_or { else if p.tok == .logical_or {
p.gen(' or ') p.gen(' or ')
} }
} else { }
else {
p.gen(' ${p.tok.str()} ') p.gen(' ${p.tok.str()} ')
} }
p.check_space(p.tok) p.check_space(p.tok)
@ -47,12 +51,10 @@ fn (p mut Parser) bterm() string {
ph := p.cgen.add_placeholder() ph := p.cgen.add_placeholder()
mut typ := p.expression() mut typ := p.expression()
p.expected_type = typ p.expected_type = typ
is_str := typ=='string' && !p.is_sql is_str := typ == 'string' && !p.is_sql
is_ustr := typ=='ustring' is_ustr := typ == 'ustring'
base := p.base_type(typ) base := p.base_type(typ)
is_float := base[0] == `f` && (base in ['f64', 'f32']) && is_float := base[0] == `f` && (base in ['f64', 'f32']) && !(p.cur_fn.name in ['f64_abs', 'f32_abs']) && p.cur_fn.name != 'eq'
!(p.cur_fn.name in ['f64_abs', 'f32_abs']) &&
p.cur_fn.name != 'eq'
is_array := typ.starts_with('array_') is_array := typ.starts_with('array_')
expr_type := base expr_type := base
tok := p.tok tok := p.tok
@ -61,14 +63,14 @@ fn (p mut Parser) bterm() string {
p.error('no = ') p.error('no = ')
} }
*/ */
if tok in [.eq, .gt, .lt, .le, .ge, .ne] { 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 { if is_array {
p.error('array comparison is not supported yet') p.error('array comparison is not supported yet')
} }
p.fspace() p.fspace()
//p.fgen(' ${p.tok.str()} ') // p.fgen(' ${p.tok.str()} ')
if (is_float || is_str || is_ustr) && !p.is_js { if (is_float || is_str || is_ustr) && !p.is_js {
p.gen(',') p.gen(',')
} }
@ -88,47 +90,85 @@ fn (p mut Parser) bterm() string {
p.check_types(p.expression(), typ) p.check_types(p.expression(), typ)
sql_param := p.cgen.cut() sql_param := p.cgen.cut()
p.sql_params << sql_param p.sql_params << sql_param
p.sql_types << typ p.sql_types << typ
//println('*** sql type: $typ | param: $sql_param') // println('*** sql type: $typ | param: $sql_param')
} else { }
else {
p.check_types(p.expression(), typ) p.check_types(p.expression(), typ)
} }
typ = 'bool' typ = 'bool'
if is_str && !p.is_js { //&& !p.is_sql { if is_str && !p.is_js {
// && !p.is_sql {
p.gen(')') p.gen(')')
match tok { match tok {
.eq { p.cgen.set_placeholder(ph, 'string_eq(') } .eq {
.ne { p.cgen.set_placeholder(ph, 'string_ne(') } p.cgen.set_placeholder(ph, 'string_eq(')
.le { p.cgen.set_placeholder(ph, 'string_le(') } }
.ge { p.cgen.set_placeholder(ph, 'string_ge(') } .ne {
.gt { p.cgen.set_placeholder(ph, 'string_gt(') } p.cgen.set_placeholder(ph, 'string_ne(')
.lt { p.cgen.set_placeholder(ph, 'string_lt(') } }
else { } .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 { if is_ustr {
p.gen(')') p.gen(')')
match tok { match tok {
.eq { p.cgen.set_placeholder(ph, 'ustring_eq(') } .eq {
.ne { p.cgen.set_placeholder(ph, 'ustring_ne(') } p.cgen.set_placeholder(ph, 'ustring_eq(')
.le { p.cgen.set_placeholder(ph, 'ustring_le(') } }
.ge { p.cgen.set_placeholder(ph, 'ustring_ge(') } .ne {
.gt { p.cgen.set_placeholder(ph, 'ustring_gt(') } p.cgen.set_placeholder(ph, 'ustring_ne(')
.lt { p.cgen.set_placeholder(ph, 'ustring_lt(') } }
else { } .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' { if is_float && p.cur_fn.name != 'f32_abs' && p.cur_fn.name != 'f64_abs' {
p.gen(')') p.gen(')')
match tok { match tok {
.eq { p.cgen.set_placeholder(ph, '${expr_type}_eq(') } .eq {
.ne { p.cgen.set_placeholder(ph, '${expr_type}_ne(') } p.cgen.set_placeholder(ph, '${expr_type}_eq(')
.le { p.cgen.set_placeholder(ph, '${expr_type}_le(') } }
.ge { p.cgen.set_placeholder(ph, '${expr_type}_ge(') } .ne {
.gt { p.cgen.set_placeholder(ph, '${expr_type}_gt(') } p.cgen.set_placeholder(ph, '${expr_type}_ne(')
.lt { p.cgen.set_placeholder(ph, '${expr_type}_lt(') } }
else { } .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 return typ
@ -142,19 +182,20 @@ fn (p mut Parser) name_expr() string {
// amp // amp
ptr := p.tok == .amp ptr := p.tok == .amp
deref := p.tok == .mul deref := p.tok == .mul
mut mul_nr := 0 mut mul_nr := 0
mut deref_nr := 0 mut deref_nr := 0
for { for {
if p.tok == .amp { if p.tok == .amp {
mul_nr++ mul_nr++
}else if p.tok == .mul { }
deref_nr++ else if p.tok == .mul {
}else { deref_nr++
break }
} else {
p.next() break
} }
p.next()
}
if p.tok == .lpar { if p.tok == .lpar {
p.gen('*'.repeat(deref_nr)) p.gen('*'.repeat(deref_nr))
p.gen('(') p.gen('(')
@ -162,7 +203,7 @@ fn (p mut Parser) name_expr() string {
mut temp_type := p.bool_expression() mut temp_type := p.bool_expression()
p.gen(')') p.gen(')')
p.check(.rpar) p.check(.rpar)
for _ in 0..deref_nr { for _ in 0 .. deref_nr {
temp_type = temp_type.replace_once('*', '') temp_type = temp_type.replace_once('*', '')
} }
return temp_type return temp_type
@ -194,15 +235,15 @@ fn (p mut Parser) name_expr() string {
p.check(.dot) p.check(.dot)
name = p.lit name = p.lit
// C struct initialization // 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) { if !p.table.known_type(name) {
p.error('unknown C type `$name`, ' + p.error('unknown C type `$name`, ' + 'define it with `struct C.$name { ... }`')
'define it with `struct C.$name { ... }`')
} }
return p.get_struct_type(name, true, ptr) return p.get_struct_type(name, true, ptr)
} }
if ptr && p.peek() == .lpar { 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{!}`) // `&C.Foo(0)` cast (replacing old `&C.Foo{!}`)
if peek2.tok == .number && peek2.lit == '0' { if peek2.tok == .number && peek2.lit == '0' {
p.cgen.insert_before('struct /*C.Foo(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() p.check_enum_member_access()
// println("found enum value: $p.expected_type") // println("found enum value: $p.expected_type")
return 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: // 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) return p.get_var_type(name, ptr, deref_nr)
} }
// Module? // Module?
if p.peek() == .dot && (name == p.mod || if p.peek() == .dot && (name == p.mod || p.import_table.known_alias(name)) && !is_c {
p.import_table.known_alias(name)) && !is_c
{
mut mod := name mut mod := name
// must be aliased module // must be aliased module
if name != p.mod && p.import_table.known_alias(name) { 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 // Unknown name, try prepending the module name to it
// TODO perf // TODO perf
else if !p.table.known_type(name) && else if !p.table.known_type(name) && !p.table.known_fn(name) && !p.table.known_const(name) && !is_c {
!p.table.known_fn(name) && !p.table.known_const(name) && !is_c
{
name = p.prepend_mod(name) name = p.prepend_mod(name)
} }
// re-check // re-check
@ -271,18 +309,18 @@ fn (p mut Parser) name_expr() string {
// known type? int(4.5) or Color.green (enum) // known type? int(4.5) or Color.green (enum)
if p.table.known_type(name) { if p.table.known_type(name) {
// cast expression: float(5), byte(0), (*int)(ptr) etc // 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 p.peek() == .lpar || (deref && p.peek() == .rpar) {
if deref { if deref {
name += '*'.repeat(deref_nr ) name += '*'.repeat(deref_nr)
} }
else if ptr { else if ptr {
name += '*'.repeat(mul_nr) name += '*'.repeat(mul_nr)
} }
//p.gen('(') // p.gen('(')
mut typ := name mut typ := name
p.cast(typ) p.cast(typ)
//p.gen(')') // p.gen(')')
for p.tok == .dot { for p.tok == .dot {
typ = p.dot(typ, ph) 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`') p.warn('`${enum_type.name}.$val` is unnecessary, use `.$val`')
} }
// println('enum val $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() p.next()
return enum_type.name return enum_type.name
} }
@ -315,7 +353,6 @@ fn (p mut Parser) name_expr() string {
return p.get_struct_type(name, false, ptr) return p.get_struct_type(name, false, ptr)
} }
} }
// Constant // Constant
if p.table.known_const(name) { if p.table.known_const(name) {
return p.get_const_type(name, ptr) 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 // exhaused all options type,enum,const,mod,var,fn etc
// so show undefined error (also checks typos) // 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 // no () after func, so func is an argument, just gen its name
// TODO verify this and handle errors // TODO verify this and handle errors
peek := p.peek() peek := p.peek()
if peek != .lpar && peek != .lt { if peek != .lpar && peek != .lt {
// 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
} }
p.table.register_type(fn_typ) p.table.register_type(fn_typ)
p.gen(p.table.fn_gen_name(f)) p.gen(p.table.fn_gen_name(f))
p.next() p.next()
return f.typ_str() //'void*' return f.typ_str() // 'void*'
} }
// TODO bring back // TODO bring back
if f.typ == 'void' && !p.inside_if_expr { if f.typ == 'void' && !p.inside_if_expr {
// p.error('`$f.name` used as value') // p.error('`$f.name` used as value')
} }
fn_call_ph := p.cgen.add_placeholder() fn_call_ph := p.cgen.add_placeholder()
// println('call to fn $f.name of type $f.typ') // println('call to fn $f.name of type $f.typ')
// TODO replace the following dirty hacks (needs ptr access to fn table) // 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') // println(' from $f2.name(${f2.str_args(p.table)}) $f2.typ : $f2.type_inst')
} }
f = new_f f = new_f
// optional function call `function() or {}`, no return assignment // optional function call `function() or {}`, no return assignment
is_or_else := p.tok == .key_orelse is_or_else := p.tok == .key_orelse
if p.tok == .question { if p.tok == .question {
@ -375,12 +412,10 @@ fn (p mut Parser) name_expr() string {
else if !p.is_var_decl && is_or_else { else if !p.is_var_decl && is_or_else {
f.typ = p.gen_handle_option_or_else(f.typ, '', fn_call_ph) 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 && else if !p.is_var_decl && !is_or_else && !p.inside_return_expr && f.typ.starts_with('Option_') {
f.typ.starts_with('Option_') { opt_type := f.typ[7..]
opt_type := f.typ[7..] p.error('unhandled option type: `?$opt_type`')
p.error('unhandled option type: `?$opt_type`') }
}
// dot after a function call: `get_user().age` // dot after a function call: `get_user().age`
if p.tok == .dot { if p.tok == .dot {
mut typ := '' mut typ := ''
@ -390,8 +425,7 @@ fn (p mut Parser) name_expr() string {
} }
return typ return typ
} }
//p.log('end of name_expr') // p.log('end of name_expr')
if f.typ.ends_with('*') { if f.typ.ends_with('*') {
p.is_alloc = true p.is_alloc = true
} }
@ -401,14 +435,14 @@ fn (p mut Parser) name_expr() string {
// returns resulting type // returns resulting type
fn (p mut Parser) expression() string { fn (p mut Parser) expression() string {
p.is_const_literal = true p.is_const_literal = true
//if p.scanner.file_path.contains('test_test') { // if p.scanner.file_path.contains('test_test') {
//println('expression() pass=$p.pass tok=') // println('expression() pass=$p.pass tok=')
//p.print_tok() // p.print_tok()
//} // }
ph := p.cgen.add_placeholder() ph := p.cgen.add_placeholder()
typ := p.indot_expr() typ := p.indot_expr()
is_str := typ=='string' is_str := typ == 'string'
is_ustr := typ=='ustring' is_ustr := typ == 'ustring'
// `a << b` ==> `array_push(&a, b)` // `a << b` ==> `array_push(&a, b)`
if p.tok == .left_shift { if p.tok == .left_shift {
if typ.contains('array_') { if typ.contains('array_') {
@ -416,17 +450,16 @@ fn (p mut Parser) expression() string {
// a << 7 => int tmp = 7; array_push(&a, &tmp); // a << 7 => int tmp = 7; array_push(&a, &tmp);
// _PUSH(&a, expression(), tmp, string) // _PUSH(&a, expression(), tmp, string)
tmp := p.get_tmp() 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) p.check_space(.left_shift)
// Get the value we are pushing // Get the value we are pushing
p.gen(', (') p.gen(', (')
// Immutable? Can we push? // Immutable? Can we push?
if !p.expr_var.is_mut && !p.pref.translated { 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_') { 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 "+ p.error("for now it's not possible to append an element to " + 'a mutable array argument `$p.expr_var.name`')
'a mutable array argument `$p.expr_var.name`')
} }
if !p.expr_var.is_changed { if !p.expr_var.is_changed {
p.mark_var_changed(p.expr_var) p.mark_var_changed(p.expr_var)
@ -443,7 +476,7 @@ fn (p mut Parser) expression() string {
return 'void' return 'void'
} }
else { else {
if !is_integer_type(typ) { if !is_integer_type(typ) {
t := p.table.find_type(typ) t := p.table.find_type(typ)
if t.cat != .enum_ { if t.cat != .enum_ {
p.error('cannot use shift operator on non-integer type `$typ`') 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 p.tok == .righ_shift {
if !is_integer_type(typ) { if !is_integer_type(typ) {
t := p.table.find_type(typ) t := p.table.find_type(typ)
if t.cat != .enum_ { if t.cat != .enum_ {
p.error('cannot use shift operator on non-integer type `$typ`') p.error('cannot use shift operator on non-integer type `$typ`')
@ -473,7 +506,7 @@ fn (p mut Parser) expression() string {
if typ == 'bool' { if typ == 'bool' {
p.error('operator ${p.tok.str()} not defined on 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) p.check_space(p.tok)
if is_str && tok_op == .plus && !p.is_js { if is_str && tok_op == .plus && !p.is_js {
p.is_alloc = true p.is_alloc = true
@ -490,15 +523,16 @@ fn (p mut Parser) expression() string {
// Msvc errors on void* pointer arithmatic // Msvc errors on void* pointer arithmatic
// ... So cast to byte* and then do the add // ... So cast to byte* and then do the add
p.cgen.set_placeholder(ph, '(byte*)') 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()) p.gen(tok_op.str())
} }
// Vec + Vec // Vec + Vec
else { else {
if p.pref.translated { 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 { else {
p.gen(',') p.gen(',')
@ -510,10 +544,10 @@ fn (p mut Parser) expression() string {
expr_type := p.term() expr_type := p.term()
open := tok_op == .amp && p.tok in [.eq, .ne] // force precedence `(a & b) == c` //false open := tok_op == .amp && p.tok in [.eq, .ne] // force precedence `(a & b) == c` //false
if tok_op in [.pipe, .amp, .xor] { 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') p.error('operator ${tok_op.str()} is defined only on integer types')
} }
//open = true // open = true
} }
if open { if open {
p.cgen.set_placeholder(ph, '(') p.cgen.set_placeholder(ph, '(')
@ -528,15 +562,19 @@ fn (p mut Parser) expression() string {
// Make sure operators are used with correct types // Make sure operators are used with correct types
if !p.pref.translated && !is_str && !is_ustr && !is_num { if !p.pref.translated && !is_str && !is_ustr && !is_num {
T := p.table.find_type(typ) T := p.table.find_type(typ)
if tok_op == .plus { p.handle_operator('+', typ, 'op_plus', ph, T) } if tok_op == .plus {
else if tok_op == .minus { p.handle_operator('-', typ, 'op_minus', ph, T) } p.handle_operator('+', typ, 'op_plus', ph, T)
}
else if tok_op == .minus {
p.handle_operator('-', typ, 'op_minus', ph, T)
}
} }
} }
return typ return typ
} }
fn (p mut Parser) handle_operator(op string, typ string, cpostfix string, ph int, T &Type) { 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.cgen.set_placeholder(ph, '${typ}_${cpostfix}(')
p.gen(')') 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 { fn (p mut Parser) term() string {
line_nr := p.scanner.line_nr line_nr := p.scanner.line_nr
//if p.fileis('fn_test') { // if p.fileis('fn_test') {
//println('\nterm() $line_nr') // println('\nterm() $line_nr')
//} // }
ph := p.cgen.add_placeholder() ph := p.cgen.add_placeholder()
typ := p.unary() typ := p.unary()
//if p.fileis('fn_test') { // if p.fileis('fn_test') {
//println('2: $line_nr') // println('2: $line_nr')
//} // }
// `*` on a newline? Can't be multiplication, only dereference // `*` on a newline? Can't be multiplication, only dereference
if p.tok == .mul && line_nr != p.scanner.line_nr { if p.tok == .mul && line_nr != p.scanner.line_nr {
return typ return typ
@ -566,7 +604,7 @@ fn (p mut Parser) term() string {
is_mod := tok == .mod is_mod := tok == .mod
p.fspace() p.fspace()
p.next() p.next()
p.gen(tok.str())// + ' /*op2*/ ') p.gen(tok.str()) // + ' /*op2*/ ')
oph := p.cgen.add_placeholder() oph := p.cgen.add_placeholder()
p.fspace() p.fspace()
if (is_div || is_mod) && p.tok == .number && p.lit == '0' { 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) p.check_types(expr_type, typ)
T := p.table.find_type(typ) T := p.table.find_type(typ)
// NB: oph is a char index just after the OP // 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..] after_oph := p.cgen.cur_line[oph..]
p.cgen.cur_line = before_oph + ',' + after_oph p.cgen.cur_line = before_oph + ',' + after_oph
match tok { match tok {
.mul { p.handle_operator('*', typ, 'op_mul', ph, T) } .mul {
.div { p.handle_operator('/', typ, 'op_div', ph, T) } p.handle_operator('*', typ, 'op_mul', ph, T)
.mod { p.handle_operator('%', typ, 'op_mod', ph, T) } }
else {} .div {
} p.handle_operator('/', typ, 'op_div', ph, T)
}
.mod {
p.handle_operator('%', typ, 'op_mod', ph, T)
}
else {
}}
continue continue
} }
if is_mod { if is_mod {
if !(is_integer_type(expr_type) && is_integer_type(typ)) { if !(is_integer_type(expr_type) && is_integer_type(typ)) {
p.error('operator `mod` requires integer types') p.error('operator `mod` requires integer types')
} }
} else { }
else {
p.check_types(expr_type, typ) p.check_types(expr_type, typ)
} }
} }
@ -607,24 +651,23 @@ fn (p mut Parser) unary() string {
mut typ := '' mut typ := ''
tok := p.tok tok := p.tok
match tok { match tok {
.not { .not {
p.gen('!') p.gen('!')
p.check(.not) p.check(.not)
// typ should be bool type // typ should be bool type
typ = p.indot_expr() typ = p.indot_expr()
if typ != 'bool' { if typ != 'bool' {
p.error('operator ! requires bool type, not `$typ`') p.error('operator ! requires bool type, not `$typ`')
}
} }
} .bit_not {
.bit_not { p.gen('~')
p.gen('~') p.check(.bit_not)
p.check(.bit_not) typ = p.bool_expression()
typ = p.bool_expression() }
} else {
else { typ = p.factor()
typ = p.factor() }}
}
}
return typ return typ
} }
@ -632,72 +675,72 @@ fn (p mut Parser) factor() string {
mut typ := '' mut typ := ''
tok := p.tok tok := p.tok
match tok { match tok {
.key_none { .key_none {
if !p.expected_type.starts_with('Option_') { if !p.expected_type.starts_with('Option_') {
p.error('need "$p.expected_type" got none') 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'
} }
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) { .number {
p.error('constant `$p.lit` overflows `$p.expected_type`') typ = 'int'
} // Check if float (`1.0`, `1e+3`) but not if is hexa
p.gen(p.lit) 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'
.minus { // typ = 'f64' // TODO
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') else {
return p.js_decode() 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') { .minus {
//println('ORM name: $p.lit') p.gen('-')
//} p.next()
typ = p.name_expr() return p.factor()
return typ // 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 { .key_default {
p.next() p.next()
p.next() p.next()
@ -710,71 +753,71 @@ fn (p mut Parser) factor() string {
return 'T' return 'T'
} }
*/ */
.lpar {
//p.gen('(/*lpar*/') .lpar {
p.gen('(') // p.gen('(/*lpar*/')
p.check(.lpar) p.gen('(')
typ = p.bool_expression() p.check(.lpar)
// Hack. If this `)` referes to a ptr cast `(*int__)__`, it was already checked typ = p.bool_expression()
// TODO: fix parser so that it doesn't think it's a par expression when it sees `(` in // Hack. If this `)` referes to a ptr cast `(*int__)__`, it was already checked
// __(__*int)( // TODO: fix parser so that it doesn't think it's a par expression when it sees `(` in
if !p.ptr_cast { // __(__*int)(
p.check(.rpar) if !p.ptr_cast {
p.check(.rpar)
}
p.ptr_cast = false
p.gen(')')
return typ
} }
p.ptr_cast = false .chartoken {
p.gen(')') p.char_expr()
return typ typ = 'byte'
} 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()
} }
// { user | name :'new name' } .str {
return p.assoc() p.string_expr()
} typ = 'string'
.key_if { return typ
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()}`') .key_false {
} typ = 'bool'
} p.gen('0')
p.next()// TODO everything should next() }
.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 return typ
} }

View File

@ -277,6 +277,9 @@ fn (p mut Parser) if_statement(is_expr bool, elif_depth int) string {
} }
p.fspace() p.fspace()
p.check(.lcbr) p.check(.lcbr)
if p.inside_if_expr {
p.fspace()
}
mut typ := '' mut typ := ''
// if { if hack // if { if hack
if p.tok == .key_if && p.inside_if_expr { 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 if_returns := p.returns
p.returns = false p.returns = false
if p.tok == .key_else { if p.tok == .key_else {
if !p.inside_if_expr { if p.inside_if_expr {
p.fspace()
} else {
p.fgen_nl() p.fgen_nl()
} }
p.check(.key_else) 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.genln(' else { ')
} }
p.check(.lcbr) p.check(.lcbr)
if is_expr {
p.fspace()
}
// statements() returns the type of the last statement // statements() returns the type of the last statement
first_typ := typ first_typ := typ
typ = p.statements() typ = p.statements()

View File

@ -7,6 +7,7 @@ import (
os os
strings strings
compiler.x64 compiler.x64
//time
) )
struct Parser { struct Parser {
@ -212,7 +213,9 @@ fn (v mut V) new_parser(scanner &Scanner) Parser {
return p return p
} }
// __global scan_time i64
fn (p mut Parser) scan_tokens() { fn (p mut Parser) scan_tokens() {
//t := time.ticks()
for { for {
res := p.scanner.scan() res := p.scanner.scan()
p.tokens << Token{ p.tokens << Token{
@ -225,6 +228,8 @@ fn (p mut Parser) scan_tokens() {
break break
} }
} }
// scan_time += time.ticks() - t
// println('scan tokens $p.file_name $scan_time ')
} }
fn (p mut Parser) set_current_fn(f Fn) { fn (p mut Parser) set_current_fn(f Fn) {
@ -866,6 +871,9 @@ fn (p &Parser) strtok() string {
return "'$p.lit'" return "'$p.lit'"
} }
} }
if p.tok == .hash {
return '#' + p.lit
}
res := p.tok.str() res := p.tok.str()
if res == '' { if res == '' {
n := int(p.tok) n := int(p.tok)
@ -967,7 +975,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
} }
@ -1165,6 +1173,9 @@ fn (p mut Parser) statements_no_rcbr() string {
} }
} }
// p.next() // p.next()
if p.inside_if_expr {
p.fspace()
}
p.check(.rcbr) p.check(.rcbr)
// p.fmt_dec() // p.fmt_dec()
p.close_scope() p.close_scope()
@ -1821,12 +1832,12 @@ fn (p mut Parser) var_expr(v Var) string {
if p.tok == .lsbr { if p.tok == .lsbr {
typ = p.index_expr(typ, fn_ph) typ = p.index_expr(typ, fn_ph)
if p.base_type(typ).starts_with('fn ') && p.tok == .lpar { if p.base_type(typ).starts_with('fn ') && p.tok == .lpar {
T := p.table.find_type(p.base_type(typ)) T := p.table.find_type(p.base_type(typ))
p.gen('(') p.gen('(')
p.fn_call_args(mut T.func) p.fn_call_args(mut T.func)
p.gen(')') p.gen(')')
typ = T.func.typ typ = T.func.typ
} }
} }
// a.b.c().d chain // a.b.c().d chain
// mut dc := 0 // mut dc := 0

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
fn (p mut Parser) string_expr() { fn (p mut Parser) string_expr() {
@ -13,12 +12,13 @@ fn (p mut Parser) string_expr() {
str := p.lit str := p.lit
// No ${}, just return a simple string // No ${}, just return a simple string
if p.peek() != .str_dollar || is_raw { 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");` // `C.puts('hi')` => `puts("hi");`
/* /*
Calling a C function sometimes requires a call to a string method Calling a C function sometimes requires a call to a string method
C.fun('ssss'.to_wide()) => fun(string_to_wide(tos3("ssss"))) 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') { if (p.calling_c && p.peek() != .dot) || is_cstr || (p.pref.translated && p.mod == 'main') {
p.gen('"$f"') p.gen('"$f"')
} }
@ -40,12 +40,12 @@ fn (p mut Parser) string_expr() {
p.is_alloc = true // $ interpolation means there's allocation p.is_alloc = true // $ interpolation means there's allocation
mut args := '"' mut args := '"'
mut format := '"' mut format := '"'
mut complex_inter := false // for vfmt mut complex_inter := false // for vfmt
for p.tok == .str { for p.tok == .str {
// Add the string between %d's // Add the string between %d's
p.lit = p.lit.replace('%', '%%') p.lit = p.lit.replace('%', '%%')
format += format_str(p.lit) format += format_str(p.lit)
p.next()// skip $ p.next() // skip $
if p.tok != .str_dollar { if p.tok != .str_dollar {
continue continue
} }
@ -58,7 +58,7 @@ fn (p mut Parser) string_expr() {
complex_inter = true complex_inter = true
} }
// Get bool expr inside a temp var // Get bool expr inside a temp var
typ, val_ := p.tmp_expr() typ,val_ := p.tmp_expr()
val := val_.trim_space() val := val_.trim_space()
args += ', $val' args += ', $val'
if typ == 'string' { if typ == 'string' {
@ -70,7 +70,7 @@ fn (p mut Parser) string_expr() {
args += '.len, ${val}.s.str' args += '.len, ${val}.s.str'
} }
if typ == 'bool' { if typ == 'bool' {
//args += '.len, ${val}.str' // args += '.len, ${val}.str'
} }
// Custom format? ${t.hour:02d} // Custom format? ${t.hour:02d}
custom := p.tok == .colon custom := p.tok == .colon
@ -81,16 +81,17 @@ fn (p mut Parser) string_expr() {
cformat += '.' cformat += '.'
p.next() p.next()
} }
if p.tok == .minus { // support for left aligned formatting if p.tok == .minus {
// support for left aligned formatting
cformat += '-' cformat += '-'
p.next() p.next()
} }
cformat += p.lit// 02 cformat += p.lit // 02
p.next() p.next()
fspec := p.lit // f fspec := p.lit // f
cformat += fspec cformat += fspec
if fspec == 's' { 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' { if typ != 'string' {
p.error('only V strings can be formatted with a :${cformat} format, but you have given "${val}", which has type ${typ}') 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 format += f
} }
//println('interpolation format is: |${format}| args are: |${args}| ') // println('interpolation format is: |${format}| args are: |${args}| ')
} }
if complex_inter { if complex_inter {
p.fgen('}') p.fgen('}')
} }
//p.fgen('\'') // p.fgen('\'')
// println("hello %d", num) optimization. // println("hello %d", num) optimization.
if p.cgen.nogen { if p.cgen.nogen {
return return
@ -151,4 +152,3 @@ fn (p mut Parser) string_expr() {
p.gen('_STR($format$args)') p.gen('_STR($format$args)')
} }
} }

View File

@ -243,7 +243,7 @@ fn (p &Parser) gen_fmt() {
if s == '' { if s == '' {
return return
} }
if !p.file_name.contains('parser.v') {return} //if !p.file_name.contains('float.v') {return}
path := os.tmpdir() + '/' + p.file_name path := os.tmpdir() + '/' + p.file_name
println('generating ${path}') println('generating ${path}')
mut out := os.create(path) or { mut out := os.create(path) or {

View File

@ -1,20 +1,21 @@
module strings module strings
#-js //#-js
// use levenshtein distance algorithm to calculate // use levenshtein distance algorithm to calculate
// the distance between between two strings (lower is closer) // the distance between between two strings (lower is closer)
pub fn levenshtein_distance(a, b string) int { 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 { for ca in a {
mut j := 1 mut j := 1
mut fj1 := f[0] mut fj1 := f[0]
f[0]++ f[0]++
for cb in b { 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 { if cb != ca {
mn = if mn <= fj1+1 { mn } else { fj1+1 } mn = if mn <= fj1 + 1 { mn } else { fj1 + 1 }
} else { }
else {
mn = if mn <= fj1 { mn } else { fj1 } mn = if mn <= fj1 { mn } else { fj1 }
} }
fj1 = f[j] fj1 = f[j]
@ -22,7 +23,7 @@ pub fn levenshtein_distance(a, b string) int {
j++ j++
} }
} }
return f[f.len-1] return f[f.len - 1]
} }
// use levenshtein distance algorithm to calculate // 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 { pub fn levenshtein_distance_percentage(a, b string) f32 {
d := levenshtein_distance(a, b) d := levenshtein_distance(a, b)
l := if a.len >= b.len { a.len } else { b.len } 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ørensenDice coefficient. // implementation of SørensenDice coefficient.
// find the similarity between two strings. // find the similarity between two strings.
// returns coefficient between 0.0 (not similar) and 1.0 (exact match). // returns coefficient between 0.0 (not similar) and 1.0 (exact match).
pub fn dice_coefficient(s1, s2 string) f32 { pub fn dice_coefficient(s1, s2 string) f32 {
if s1.len == 0 || s2.len == 0 { return 0.0 } if s1.len == 0 || s2.len == 0 {
if s1 == s2 { return 1.0 } return 0.0
if s1.len < 2 || s2.len < 2 { 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 } a := if s1.len > s2.len { s1 } else { s2 }
b := if a == s1 { s2 } else { s1 } b := if a == s1 { s2 } else { s1 }
mut first_bigrams := map[string]int mut first_bigrams := map[string]int
for i := 0; i < a.len-1; i++ { for i := 0; i < a.len - 1; i++ {
bigram := a[i..i+2] bigram := a[i..i + 2]
q := if bigram in first_bigrams { q := if bigram in first_bigrams { first_bigrams[bigram] + 1 } else { 1 }
first_bigrams[bigram]+1 } else { 1 }
first_bigrams[bigram] = q first_bigrams[bigram] = q
} }
mut intersection_size := 0 mut intersection_size := 0
for i := 0; i < b.len-1; i++ { for i := 0; i < b.len - 1; i++ {
bigram := b[i..i+2] bigram := b[i..i + 2]
count := if bigram in first_bigrams { first_bigrams[bigram] } else { 0 } count := if bigram in first_bigrams { first_bigrams[bigram] } else { 0 }
if count > 0 { if count > 0 {
first_bigrams[bigram] = count - 1 first_bigrams[bigram] = count - 1