mirror of
https://github.com/vlang/v.git
synced 2025-09-14 06:52:36 +03:00
JavaSript backend (early stage)
This commit is contained in:
parent
982a162fbf
commit
5cc81b91cb
31 changed files with 1818 additions and 584 deletions
|
@ -65,6 +65,7 @@ mut:
|
|||
cur_gen_type string // "App" to replace "T" in current generic function
|
||||
is_vweb bool
|
||||
is_sql bool
|
||||
is_js bool
|
||||
sql_i int // $1 $2 $3
|
||||
sql_params []string // ("select * from users where id = $1", ***"100"***)
|
||||
sql_types []string // int, string and so on; see sql_params
|
||||
|
@ -108,6 +109,9 @@ fn (v mut V) new_parser(path string) Parser {
|
|||
vroot: v.vroot
|
||||
|
||||
}
|
||||
$if js {
|
||||
p.is_js = true
|
||||
}
|
||||
|
||||
if p.pref.is_repl {
|
||||
p.scanner.should_print_line_on_error = false
|
||||
|
@ -1245,7 +1249,7 @@ fn ($v.name mut $v.typ) $p.cur_fn.name (...) {
|
|||
p.gen(' = ')
|
||||
}
|
||||
case Token.plus_assign:
|
||||
if is_str {
|
||||
if is_str && !p.is_js {
|
||||
p.gen('= string_add($v.name, ')// TODO can't do `foo.bar += '!'`
|
||||
}
|
||||
else {
|
||||
|
@ -1275,7 +1279,7 @@ fn ($v.name mut $v.typ) $p.cur_fn.name (...) {
|
|||
p.scanner.line_nr--
|
||||
p.error('cannot use type `$expr_type` as type `$p.assigned_type` in assignment')
|
||||
}
|
||||
if is_str && tok == .plus_assign {
|
||||
if is_str && tok == .plus_assign && !p.is_js {
|
||||
p.gen(')')
|
||||
}
|
||||
// p.assigned_var = ''
|
||||
|
@ -1310,38 +1314,7 @@ fn (p mut Parser) var_decl() {
|
|||
p.error('variable names cannot contain uppercase letters, use snake_case instead')
|
||||
}
|
||||
p.check_space(.decl_assign) // :=
|
||||
// Generate expression to tmp because we need its type first
|
||||
// [TYP .name =] bool_expression()
|
||||
pos := p.cgen.add_placeholder()
|
||||
mut typ := p.bool_expression()
|
||||
// Option check ? or {
|
||||
or_else := p.tok == .key_orelse
|
||||
tmp := p.get_tmp()
|
||||
if or_else {
|
||||
// Option_User tmp = get_user(1);
|
||||
// if (!tmp.ok) { or_statement }
|
||||
// User user = *(User*)tmp.data;
|
||||
// p.assigned_var = ''
|
||||
p.cgen.set_placeholder(pos, '$typ $tmp = ')
|
||||
p.genln(';')
|
||||
typ = typ.replace('Option_', '')
|
||||
p.next()
|
||||
p.check(.lcbr)
|
||||
p.genln('if (!$tmp .ok) {')
|
||||
p.register_var(Var {
|
||||
name: 'err'
|
||||
typ: 'string'
|
||||
is_mut: false
|
||||
is_used: true
|
||||
})
|
||||
p.genln('string err = $tmp . error;')
|
||||
p.statements()
|
||||
p.genln('$typ $name = *($typ*) $tmp . data;')
|
||||
if !p.returns && p.prev_tok2 != .key_continue && p.prev_tok2 != .key_break {
|
||||
p.error('`or` block must return/continue/break/panic')
|
||||
}
|
||||
p.returns = false
|
||||
}
|
||||
typ := p.gen_var_decl(name, is_static)
|
||||
p.register_var(Var {
|
||||
name: name
|
||||
typ: typ
|
||||
|
@ -1349,18 +1322,6 @@ fn (p mut Parser) var_decl() {
|
|||
is_alloc: p.is_alloc
|
||||
})
|
||||
//if p.is_alloc { println('REG VAR IS ALLOC $name') }
|
||||
if !or_else {
|
||||
gen_name := p.table.var_cgen_name(name)
|
||||
mut nt_gen := p.table.cgen_name_type_pair(gen_name, typ)
|
||||
// `foo := C.Foo{}` => `Foo foo;`
|
||||
if !p.is_empty_c_struct_init {
|
||||
nt_gen += '='
|
||||
}
|
||||
if is_static {
|
||||
nt_gen = 'static $nt_gen'
|
||||
}
|
||||
p.cgen.set_placeholder(pos, nt_gen)
|
||||
}
|
||||
p.var_decl_name = ''
|
||||
p.is_empty_c_struct_init = false
|
||||
}
|
||||
|
@ -1415,7 +1376,7 @@ fn (p mut Parser) bterm() string {
|
|||
// if tok in [ .eq, .gt, .lt, .le, .ge, .ne] {
|
||||
if tok == .eq || tok == .gt || tok == .lt || tok == .le || tok == .ge || tok == .ne {
|
||||
p.fgen(' ${p.tok.str()} ')
|
||||
if is_str {
|
||||
if is_str && !p.is_js {
|
||||
p.gen(',')
|
||||
}
|
||||
else if p.is_sql && tok == .eq {
|
||||
|
@ -1439,7 +1400,7 @@ fn (p mut Parser) bterm() string {
|
|||
p.check_types(p.expression(), typ)
|
||||
}
|
||||
typ = 'bool'
|
||||
if is_str { //&& !p.is_sql {
|
||||
if is_str && !p.is_js { //&& !p.is_sql {
|
||||
p.gen(')')
|
||||
switch tok {
|
||||
case Token.eq: p.cgen.set_placeholder(ph, 'string_eq(')
|
||||
|
@ -1575,7 +1536,8 @@ fn (p mut Parser) name_expr() string {
|
|||
name += '*'
|
||||
}
|
||||
p.gen('(')
|
||||
mut typ := p.cast(name)
|
||||
mut typ := name
|
||||
p.cast(name)
|
||||
p.gen(')')
|
||||
for p.tok == .dot {
|
||||
typ = p.dot(typ, ph)
|
||||
|
@ -1604,7 +1566,8 @@ fn (p mut Parser) name_expr() string {
|
|||
if name == 'T' {
|
||||
name = p.cur_gen_type
|
||||
}
|
||||
return p.struct_init(name, is_c_struct_init)
|
||||
p.is_c_struct_init = is_c_struct_init
|
||||
return p.struct_init(name)
|
||||
}
|
||||
}
|
||||
if is_c {
|
||||
|
@ -1698,7 +1661,7 @@ fn (p mut Parser) name_expr() string {
|
|||
func: f
|
||||
}
|
||||
p.table.register_type2(fn_typ)
|
||||
p.gen(p.table.cgen_name(f))
|
||||
p.gen(p.table.fn_gen_name(f))
|
||||
p.next()
|
||||
return f.typ_str() //'void*'
|
||||
}
|
||||
|
@ -1858,7 +1821,7 @@ fn (p mut Parser) dot(str_typ string, method_ph int) string {
|
|||
}
|
||||
mut dot := '.'
|
||||
if str_typ.ends_with('*') || str_typ == 'FT_Face' { // TODO fix C ptr typedefs
|
||||
dot = '->'
|
||||
dot = dot_ptr
|
||||
}
|
||||
// field
|
||||
if has_field {
|
||||
|
@ -1917,6 +1880,27 @@ struct $f.parent_fn {
|
|||
return method.typ
|
||||
}
|
||||
|
||||
enum IndexType {
|
||||
none
|
||||
str
|
||||
map
|
||||
array
|
||||
array0
|
||||
fixed_array
|
||||
ptr
|
||||
}
|
||||
|
||||
fn get_index_type(typ string) IndexType {
|
||||
if typ.starts_with('map_') { return IndexType.map }
|
||||
if typ == 'string' { return IndexType.str }
|
||||
if typ.starts_with('array_') || typ == 'array' { return IndexType.array }
|
||||
if typ == 'byte*' || typ == 'byteptr' || typ.contains('*') {
|
||||
return IndexType.ptr
|
||||
}
|
||||
if typ[0] == `[` { return IndexType.fixed_array }
|
||||
return IndexType.none
|
||||
}
|
||||
|
||||
fn (p mut Parser) index_expr(typ_ string, fn_ph int) string {
|
||||
mut typ := typ_
|
||||
// a[0]
|
||||
|
@ -1974,34 +1958,10 @@ fn (p mut Parser) index_expr(typ_ string, fn_ph int) string {
|
|||
}
|
||||
}
|
||||
if is_arr {
|
||||
//p.fgen('[')
|
||||
// array_int a; a[0]
|
||||
// type is "array_int", need "int"
|
||||
// typ = typ.replace('array_', '')
|
||||
if is_arr0 {
|
||||
if p.fileis('int_test') {
|
||||
println('\nRRRR0 $typ')
|
||||
}
|
||||
typ = typ.right(6)
|
||||
if p.fileis('int_test') {
|
||||
println('RRRR $typ')
|
||||
}
|
||||
}
|
||||
// array a; a.first() voidptr
|
||||
// type is "array", need "void*"
|
||||
if typ == 'array' {
|
||||
typ = 'void*'
|
||||
}
|
||||
// No bounds check in translated from C code
|
||||
if p.pref.translated && !p.builtin_mod{
|
||||
// Cast void* to typ*: add (typ*) to the beginning of the assignment :
|
||||
// ((int*)a.data = ...
|
||||
p.cgen.set_placeholder(fn_ph, '(($typ*)(')
|
||||
p.gen('.data))[')
|
||||
}
|
||||
else {
|
||||
p.gen(',')
|
||||
}
|
||||
}
|
||||
p.gen_array_at(typ, is_arr0, fn_ph)
|
||||
}
|
||||
// map is tricky
|
||||
// need to replace "m[key] = val" with "tmp = val; map_set(&m, key, &tmp)"
|
||||
|
@ -2050,43 +2010,14 @@ fn (p mut Parser) index_expr(typ_ string, fn_ph int) string {
|
|||
if is_indexer && is_str && !p.builtin_mod {
|
||||
p.error('strings are immutable')
|
||||
}
|
||||
assign_pos := p.cgen.cur_line.len
|
||||
is_cao := p.tok ≠ .assign
|
||||
p.assigned_type = typ
|
||||
p.expected_type = typ
|
||||
assign_pos := p.cgen.cur_line.len
|
||||
is_cao := p.tok ≠ .assign
|
||||
p.assign_statement(v, fn_ph, is_indexer && (is_map || is_arr))
|
||||
// m[key] = val
|
||||
// `m[key] = val`
|
||||
if is_indexer && (is_map || is_arr) {
|
||||
// `a[0] = 7`
|
||||
// curline right now: `a , 0 = 7`
|
||||
mut val := p.cgen.cur_line.right(assign_pos)
|
||||
p.cgen.resetln(p.cgen.cur_line.left(assign_pos))
|
||||
mut cao_tmp := p.cgen.cur_line
|
||||
mut func := ''
|
||||
if is_map {
|
||||
func = 'map__set(&'
|
||||
// CAO on map is a bit more complicated as it loads
|
||||
// the value inside a pointer instead of returning it.
|
||||
}
|
||||
else {
|
||||
if is_ptr {
|
||||
func = 'array_set('
|
||||
if is_cao {
|
||||
cao_tmp = '*($p.expected_type *) array__get(*$cao_tmp)'
|
||||
}
|
||||
}
|
||||
else {
|
||||
func = 'array_set(&/*q*/'
|
||||
if is_cao {
|
||||
cao_tmp = '*($p.expected_type *) array__get($cao_tmp)'
|
||||
}
|
||||
}
|
||||
}
|
||||
p.cgen.set_placeholder(fn_ph, func)
|
||||
if is_cao {
|
||||
val = cao_tmp + val.all_before('=') + val.all_after('=')
|
||||
}
|
||||
p.gen(', & ($typ []) { $val })')
|
||||
p.gen_array_set(typ, is_ptr, is_map, fn_ph, assign_pos, is_cao)
|
||||
}
|
||||
return typ
|
||||
}
|
||||
|
@ -2095,52 +2026,26 @@ fn (p mut Parser) index_expr(typ_ string, fn_ph int) string {
|
|||
// }
|
||||
// m[key]. no =, just a getter
|
||||
else if (is_map || is_arr || (is_str && !p.builtin_mod)) && is_indexer {
|
||||
// Erase var name we generated earlier: "int a = m, 0"
|
||||
// "m, 0" gets killed since we need to start from scratch. It's messy.
|
||||
// "m, 0" is an index expression, save it before deleting and insert later in map_get()
|
||||
mut index_expr := ''
|
||||
if p.cgen.is_tmp {
|
||||
index_expr = p.cgen.tmp_line.right(fn_ph)
|
||||
p.cgen.resetln(p.cgen.tmp_line.left(fn_ph))
|
||||
} else {
|
||||
index_expr = p.cgen.cur_line.right(fn_ph)
|
||||
p.cgen.resetln(p.cgen.cur_line.left(fn_ph))
|
||||
}
|
||||
// Can't pass integer literal, because map_get() requires a void*
|
||||
tmp := p.get_tmp()
|
||||
tmp_ok := p.get_tmp()
|
||||
if is_map {
|
||||
p.gen('$tmp')
|
||||
def := type_default(typ)
|
||||
p.cgen.insert_before('$typ $tmp = $def; bool $tmp_ok = map_get($index_expr, & $tmp);')
|
||||
}
|
||||
else if is_arr {
|
||||
if p.pref.translated && !p.builtin_mod {
|
||||
p.gen('$index_expr ]')
|
||||
}
|
||||
else {
|
||||
if is_ptr {
|
||||
p.gen('( *($typ*) array__get(* $index_expr) )')
|
||||
} else {
|
||||
p.gen('( *($typ*) array__get($index_expr) )')
|
||||
}
|
||||
}
|
||||
}
|
||||
else if is_str && !p.builtin_mod {
|
||||
p.gen('string_at($index_expr)')
|
||||
}
|
||||
// Zero the string after map_get() if it's nil, numbers are automatically 0
|
||||
// This is ugly, but what can I do without generics?
|
||||
// TODO what about user types?
|
||||
if is_map && typ == 'string' {
|
||||
// p.cgen.insert_before('if (!${tmp}.str) $tmp = tos("", 0);')
|
||||
p.cgen.insert_before('if (!$tmp_ok) $tmp = tos((byte *)"", 0);')
|
||||
}
|
||||
p.index_get(typ, fn_ph, IndexCfg{
|
||||
is_arr: is_arr
|
||||
is_map: is_map
|
||||
is_ptr: is_ptr
|
||||
is_str: is_str
|
||||
})
|
||||
}
|
||||
// else if is_arr && is_indexer{}
|
||||
return typ
|
||||
}
|
||||
|
||||
struct IndexCfg {
|
||||
is_map bool
|
||||
is_str bool
|
||||
is_ptr bool
|
||||
is_arr bool
|
||||
is_arr0 bool
|
||||
|
||||
}
|
||||
|
||||
// returns resulting type
|
||||
fn (p mut Parser) expression() string {
|
||||
if p.scanner.file_path.contains('test_test') {
|
||||
|
@ -2151,7 +2056,7 @@ fn (p mut Parser) expression() string {
|
|||
ph := p.cgen.add_placeholder()
|
||||
mut typ := p.term()
|
||||
is_str := typ=='string'
|
||||
// a << b ==> array2_push(&a, b)
|
||||
// `a << b` ==> `array_push(&a, b)`
|
||||
if p.tok == .left_shift {
|
||||
if typ.contains('array_') {
|
||||
// Can't pass integer literal, because push requires a void*
|
||||
|
@ -2171,19 +2076,7 @@ fn (p mut Parser) expression() string {
|
|||
}
|
||||
expr_type := p.expression()
|
||||
// Two arrays of the same type?
|
||||
push_array := typ == expr_type
|
||||
if push_array {
|
||||
p.cgen.set_placeholder(ph, '_PUSH_MANY(&' )
|
||||
p.gen('), $tmp, $typ)')
|
||||
} else {
|
||||
p.check_types(expr_type, tmp_typ)
|
||||
// Pass tmp var info to the _PUSH macro
|
||||
// Prepend tmp initialisation and push call
|
||||
// Don't dereference if it's already a mutable array argument (`fn foo(mut []int)`)
|
||||
push_call := if typ.contains('*'){'_PUSH('} else { '_PUSH(&'}
|
||||
p.cgen.set_placeholder(ph, push_call)
|
||||
p.gen('), $tmp, $tmp_typ)')
|
||||
}
|
||||
p.gen_array_push(ph, typ, expr_type, tmp, tmp_typ)
|
||||
return 'void'
|
||||
}
|
||||
else {
|
||||
|
@ -2236,12 +2129,12 @@ fn (p mut Parser) expression() string {
|
|||
tok_op := p.tok
|
||||
is_num := typ == 'void*' || typ == 'byte*' || is_number_type(typ)
|
||||
p.check_space(p.tok)
|
||||
if is_str && tok_op == .plus {
|
||||
if is_str && tok_op == .plus && !p.is_js {
|
||||
p.cgen.set_placeholder(ph, 'string_add(')
|
||||
p.gen(',')
|
||||
}
|
||||
// 3 + 4
|
||||
else if is_num {
|
||||
else if is_num || p.is_js {
|
||||
if typ == 'void*' {
|
||||
// Msvc errors on void* pointer arithmatic
|
||||
// ... So cast to byte* and then do the add
|
||||
|
@ -2259,7 +2152,7 @@ fn (p mut Parser) expression() string {
|
|||
}
|
||||
}
|
||||
p.check_types(p.term(), typ)
|
||||
if is_str && tok_op == .plus {
|
||||
if is_str && tok_op == .plus && !p.is_js {
|
||||
p.gen(')')
|
||||
}
|
||||
// Make sure operators are used with correct types
|
||||
|
@ -2535,12 +2428,18 @@ fn (p mut Parser) string_expr() {
|
|||
else if p.is_sql {
|
||||
p.gen('\'$str\'')
|
||||
}
|
||||
else if p.is_js {
|
||||
p.gen('"$f"')
|
||||
}
|
||||
else {
|
||||
p.gen('tos2((byte*)"$f")')
|
||||
}
|
||||
p.next()
|
||||
return
|
||||
}
|
||||
$if js {
|
||||
p.error('js backend does not support string formatting yet')
|
||||
}
|
||||
// tmp := p.get_tmp()
|
||||
p.is_alloc = true // $ interpolation means there's allocation
|
||||
mut args := '"'
|
||||
|
@ -2601,7 +2500,7 @@ fn (p mut Parser) string_expr() {
|
|||
if fspec == 's' {
|
||||
//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}.')
|
||||
p.error('only V strings can be formatted with a :${cformat} format, but you have given "${val}", which has type ${typ}.')
|
||||
}
|
||||
args = args.all_before_last('${val}.len, ${val}.str') + '${val}.str'
|
||||
}
|
||||
|
@ -2741,10 +2640,10 @@ fn (p mut Parser) array_init() string {
|
|||
mut typ := ''
|
||||
new_arr_ph := p.cgen.add_placeholder()
|
||||
mut i := 0
|
||||
pos := p.cgen.cur_line.len// remember cur line to fetch first number in cgen for [0; 10]
|
||||
pos := p.cgen.cur_line.len// remember cur line to fetch first number in cgen for [0; 10]
|
||||
for p.tok != .rsbr {
|
||||
val_typ := p.bool_expression()
|
||||
// Get type of the first expression
|
||||
// Get the type of the first expression
|
||||
if i == 0 {
|
||||
typ = val_typ
|
||||
// fixed width array initialization? (`arr := [20]byte`)
|
||||
|
@ -2755,18 +2654,16 @@ fn (p mut Parser) array_init() string {
|
|||
if !nextc.is_space() {
|
||||
p.check(.rsbr)
|
||||
array_elem_typ := p.get_type()
|
||||
if p.table.known_type(array_elem_typ) {
|
||||
p.cgen.resetln('')
|
||||
p.gen('{0}')
|
||||
p.is_alloc = false
|
||||
if is_const_len {
|
||||
return '[${p.mod}__$lit]$array_elem_typ'
|
||||
}
|
||||
return '[$lit]$array_elem_typ'
|
||||
}
|
||||
else {
|
||||
if !p.table.known_type(array_elem_typ) {
|
||||
p.error('bad type `$array_elem_typ`')
|
||||
}
|
||||
p.cgen.resetln('')
|
||||
//p.gen('{0}')
|
||||
p.is_alloc = false
|
||||
if is_const_len {
|
||||
return '[${p.mod}__$lit]$array_elem_typ'
|
||||
}
|
||||
return '[$lit]$array_elem_typ'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2783,10 +2680,11 @@ fn (p mut Parser) array_init() string {
|
|||
i++
|
||||
// Repeat (a = [0;5] )
|
||||
if i == 1 && p.tok == .semicolon {
|
||||
p.warn('`[0 ; len]` syntax was removed. Use `[0].repeat(len)` instead')
|
||||
p.check_space(.semicolon)
|
||||
val := p.cgen.cur_line.right(pos)
|
||||
p.cgen.resetln(p.cgen.cur_line.left(pos))
|
||||
p.gen('array_repeat(& ($typ[]){ $val }, ')
|
||||
p.gen('array_repeat_old(& ($typ[]){ $val }, ')
|
||||
p.check_types(p.bool_expression(), 'int')
|
||||
p.gen(', sizeof($typ) )')
|
||||
p.check(.rsbr)
|
||||
|
@ -2801,7 +2699,6 @@ fn (p mut Parser) array_init() string {
|
|||
if p.tok == .name && i == 0 {
|
||||
// vals.len == 0 {
|
||||
typ = p.get_type()
|
||||
// println('.key_goT TYP after [] $typ')
|
||||
}
|
||||
// ! after array => no malloc and no copy
|
||||
no_alloc := p.tok == .not
|
||||
|
@ -2829,56 +2726,20 @@ fn (p mut Parser) array_init() string {
|
|||
// if ptr {
|
||||
// typ += '_ptr"
|
||||
// }
|
||||
mut new_arr := 'new_array_from_c_array'
|
||||
if no_alloc {
|
||||
new_arr += '_no_alloc'
|
||||
}
|
||||
|
||||
if i == 0 && p.pref.ccompiler != 'tcc' {
|
||||
p.gen(' 0 })')
|
||||
} else {
|
||||
p.gen(' })')
|
||||
}
|
||||
|
||||
// p.gen('$new_arr($vals.len, $vals.len, sizeof($typ), ($typ[$vals.len]) $c_arr );')
|
||||
// Need to do this in the second pass, otherwise it goes to the very top of the out.c file
|
||||
if !p.first_pass() {
|
||||
//if i == 0 {
|
||||
//p.cgen.set_placeholder(new_arr_ph, '$new_arr($i, $i, sizeof($typ), ($typ[]) { 0 ')
|
||||
//} else {
|
||||
// Due to a tcc bug, the length needs to be specified.
|
||||
// GCC crashes if it is.
|
||||
cast := if p.pref.ccompiler == 'tcc' { '($typ[$i])' } else { '($typ[])' }
|
||||
p.cgen.set_placeholder(new_arr_ph,
|
||||
'$new_arr($i, $i, sizeof($typ), $cast { ')
|
||||
//}
|
||||
}
|
||||
p.gen_array_init(typ, no_alloc, new_arr_ph, i)
|
||||
typ = 'array_$typ'
|
||||
p.register_array(typ)
|
||||
return typ
|
||||
}
|
||||
|
||||
fn (p mut Parser) struct_init(typ string, is_c_struct_init bool) string {
|
||||
fn (p mut Parser) struct_init(typ string) string {
|
||||
//p.gen('/* struct init */')
|
||||
p.is_struct_init = true
|
||||
t := p.table.find_type(typ)
|
||||
// TODO hack. If it's a C type, we may need to add "struct" before declaration:
|
||||
// a := &C.A{} ==> struct A* a = malloc(sizeof(struct A));
|
||||
if is_c_struct_init {
|
||||
p.is_c_struct_init = true
|
||||
if t.cat != .c_typedef {
|
||||
p.cgen.insert_before('struct /*c struct init*/')
|
||||
}
|
||||
}
|
||||
p.next()
|
||||
if p.gen_struct_init(typ, t) { return typ }
|
||||
p.scanner.fmt_out.cut(typ.len)
|
||||
ptr := typ.contains('*')
|
||||
// TODO tm struct struct bug
|
||||
if typ == 'tm' {
|
||||
p.cgen.lines[p.cgen.lines.len-1] = ''
|
||||
}
|
||||
p.check(.lcbr)
|
||||
no_star := typ.replace('*', '')
|
||||
// `user := User{foo:bar}` => `User user = (User){ .foo = bar}`
|
||||
/*
|
||||
if !ptr {
|
||||
if p.is_c_struct_init {
|
||||
// `face := C.FT_Face{}` => `FT_Face face;`
|
||||
|
@ -2891,7 +2752,7 @@ fn (p mut Parser) struct_init(typ string, is_c_struct_init bool) string {
|
|||
p.is_c_struct_init = false
|
||||
}
|
||||
else {
|
||||
p.gen('($typ) {')
|
||||
p.gen('($typ /*str init */) {')
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -2903,10 +2764,11 @@ fn (p mut Parser) struct_init(typ string, is_c_struct_init bool) string {
|
|||
p.check(.rcbr)
|
||||
return typ
|
||||
}
|
||||
p.gen('($no_star*)memdup(&($no_star) {')
|
||||
p.is_alloc = true
|
||||
//println('setting is_alloc=true (ret $typ)')
|
||||
p.gen('($t.name*)memdup(&($t.name) {')
|
||||
}
|
||||
*/
|
||||
mut did_gen_something := false
|
||||
// Loop thru all struct init keys and assign values
|
||||
// u := User{age:20, name:'bob'}
|
||||
|
@ -2924,7 +2786,7 @@ fn (p mut Parser) struct_init(typ string, is_c_struct_init bool) string {
|
|||
}
|
||||
f := t.find_field(field)
|
||||
inited_fields << field
|
||||
p.gen('.$field = ')
|
||||
p.gen_struct_field_init(field)
|
||||
p.check(.colon)
|
||||
p.fspace()
|
||||
p.check_types(p.bool_expression(), f.typ)
|
||||
|
@ -2954,7 +2816,8 @@ fn (p mut Parser) struct_init(typ string, is_c_struct_init bool) string {
|
|||
}
|
||||
// init map fields
|
||||
if field_typ.starts_with('map_') {
|
||||
p.gen('.$field.name = new_map(1, sizeof( ${field_typ.right(4)} ))')
|
||||
p.gen_struct_field_init(field.name)
|
||||
p.gen_empty_map(field_typ.right(4))
|
||||
inited_fields << field.name
|
||||
if i != t.fields.len - 1 {
|
||||
p.gen(',')
|
||||
|
@ -2964,7 +2827,8 @@ fn (p mut Parser) struct_init(typ string, is_c_struct_init bool) string {
|
|||
}
|
||||
def_val := type_default(field_typ)
|
||||
if def_val != '' && def_val != '{0}' {
|
||||
p.gen('.$field.name = $def_val')
|
||||
p.gen_struct_field_init(field.name)
|
||||
p.gen(def_val)
|
||||
if i != t.fields.len - 1 {
|
||||
p.gen(',')
|
||||
}
|
||||
|
@ -3006,74 +2870,17 @@ fn (p mut Parser) struct_init(typ string, is_c_struct_init bool) string {
|
|||
p.gen('0')
|
||||
}
|
||||
p.gen('}')
|
||||
if ptr {
|
||||
p.gen(', sizeof($no_star))')
|
||||
if ptr && !p.is_js {
|
||||
p.gen(', sizeof($t.name))')
|
||||
}
|
||||
p.check(.rcbr)
|
||||
p.is_struct_init = false
|
||||
p.is_c_struct_init = false
|
||||
return typ
|
||||
}
|
||||
|
||||
// `f32(3)`
|
||||
// tok is `f32` or `)` if `(*int)(ptr)`
|
||||
fn (p mut Parser) cast(typ string) string {
|
||||
p.next()
|
||||
pos := p.cgen.add_placeholder()
|
||||
if p.tok == .rpar {
|
||||
// skip `)` if it's `(*int)(ptr)`, not `int(a)`
|
||||
p.ptr_cast = true
|
||||
p.next()
|
||||
}
|
||||
p.check(.lpar)
|
||||
p.expected_type = typ
|
||||
expr_typ := p.bool_expression()
|
||||
// `face := FT_Face(cobj)` => `FT_Face face = *((FT_Face*)cobj);`
|
||||
casting_voidptr_to_value := expr_typ == 'void*' && typ != 'int' &&
|
||||
typ != 'byteptr' && !typ.ends_with('*')
|
||||
p.expected_type = ''
|
||||
// `string(buffer)` => `tos2(buffer)`
|
||||
// `string(buffer, len)` => `tos(buffer, len)`
|
||||
// `string(bytes_array, len)` => `tos(bytes_array.data, len)`
|
||||
is_byteptr := expr_typ == 'byte*' || expr_typ == 'byteptr'
|
||||
is_bytearr := expr_typ == 'array_byte'
|
||||
if typ == 'string' {
|
||||
if is_byteptr || is_bytearr {
|
||||
if p.tok == .comma {
|
||||
p.check(.comma)
|
||||
p.cgen.set_placeholder(pos, 'tos((byte *)')
|
||||
if is_bytearr {
|
||||
p.gen('.data')
|
||||
}
|
||||
p.gen(', ')
|
||||
p.check_types(p.expression(), 'int')
|
||||
} else {
|
||||
if is_bytearr {
|
||||
p.gen('.data')
|
||||
}
|
||||
p.cgen.set_placeholder(pos, 'tos2((byte *)')
|
||||
}
|
||||
}
|
||||
// `string(234)` => error
|
||||
else if expr_typ == 'int' {
|
||||
p.error('cannot cast `$expr_typ` to `$typ`, use `str()` method instead')
|
||||
}
|
||||
else {
|
||||
p.error('cannot cast `$expr_typ` to `$typ`')
|
||||
}
|
||||
}
|
||||
else if typ == 'byte' && expr_typ == 'string' {
|
||||
p.error('cannot cast `$expr_typ` to `$typ`, use backquotes `` to create a `$typ` or access the value of an index of `$expr_typ` using []')
|
||||
}
|
||||
else if casting_voidptr_to_value {
|
||||
p.cgen.set_placeholder(pos, '*($typ*)(')
|
||||
}
|
||||
else {
|
||||
p.cgen.set_placeholder(pos, '($typ)(')
|
||||
}
|
||||
p.check(.rpar)
|
||||
p.gen(')')
|
||||
return typ
|
||||
}
|
||||
|
||||
fn (p mut Parser) get_tmp() string {
|
||||
p.tmp_cnt++
|
||||
|
@ -3173,6 +2980,7 @@ fn (p mut Parser) for_st() {
|
|||
next_tok := p.peek()
|
||||
//debug := p.scanner.file_path.contains('r_draw')
|
||||
p.open_scope()
|
||||
i_type := if p.is_js { 'var' } else { 'int' }
|
||||
if p.tok == .lcbr {
|
||||
// Infinite loop
|
||||
p.gen('while (1) {')
|
||||
|
@ -3207,11 +3015,15 @@ fn (p mut Parser) for_st() {
|
|||
}
|
||||
// for i, val in array
|
||||
else if p.peek() == .comma {
|
||||
// for i, val in array { ==>
|
||||
//
|
||||
// array_int tmp = array;
|
||||
// for (int i = 0; i < tmp.len; i++) {
|
||||
// int val = tmp[i];
|
||||
/*
|
||||
`for i, val in array {`
|
||||
==>
|
||||
```
|
||||
array_int tmp = array;
|
||||
for (int i = 0; i < tmp.len; i++) {
|
||||
int val = tmp[i];
|
||||
```
|
||||
*/
|
||||
i := p.check_name()
|
||||
p.check(.comma)
|
||||
val := p.check_name()
|
||||
|
@ -3228,7 +3040,11 @@ fn (p mut Parser) for_st() {
|
|||
p.error('cannot range over type `$typ`')
|
||||
}
|
||||
expr := p.cgen.end_tmp()
|
||||
p.genln('$typ $tmp = $expr ;')
|
||||
if p.is_js {
|
||||
p.genln('var $tmp = $expr;')
|
||||
} else {
|
||||
p.genln('$typ $tmp = $expr;')
|
||||
}
|
||||
pad := if is_arr { 6 } else { 4 }
|
||||
var_typ := if is_str { 'byte' } else { typ.right(pad) }
|
||||
// typ = strings.Replace(typ, "_ptr", "*", -1)
|
||||
|
@ -3247,9 +3063,9 @@ fn (p mut Parser) for_st() {
|
|||
is_mut: true
|
||||
is_changed: true
|
||||
}
|
||||
//p.genln(';\nfor ($i_type $i = 0; $i < $tmp .len; $i ++) {')
|
||||
p.gen_for_header(i, tmp, var_typ, val)
|
||||
p.register_var(i_var)
|
||||
p.genln(';\nfor (int $i = 0; $i < $tmp .len; $i ++) {')
|
||||
p.genln('$var_typ $val = (($var_typ *) $tmp . data)[$i];')
|
||||
}
|
||||
else if is_map {
|
||||
i_var := Var {
|
||||
|
@ -3259,14 +3075,7 @@ fn (p mut Parser) for_st() {
|
|||
is_changed: true
|
||||
}
|
||||
p.register_var(i_var)
|
||||
p.genln('array_string keys_$tmp = map_keys(& $tmp ); ')
|
||||
p.genln('for (int l = 0; l < keys_$tmp .len; l++) {')
|
||||
p.genln(' string $i = ((string*)keys_$tmp .data)[l];')
|
||||
//p.genln(' string $i = *(string*) ( array__get(keys_$tmp, l) );')
|
||||
def := type_default(typ)
|
||||
// TODO don't call map_get() for each key, fetch values while traversing
|
||||
// the tree (replace `map_keys()` above with `map_key_vals()`)
|
||||
p.genln('$var_typ $val = $def; map_get($tmp, $i, & $val);')
|
||||
p.gen_for_map_header(i, tmp, var_typ, val, typ)
|
||||
}
|
||||
else if is_str {
|
||||
i_var := Var {
|
||||
|
@ -3276,9 +3085,7 @@ fn (p mut Parser) for_st() {
|
|||
is_changed: true
|
||||
}
|
||||
p.register_var(i_var)
|
||||
p.genln('array_byte bytes_$tmp = string_bytes( $tmp );')
|
||||
p.genln(';\nfor (int $i = 0; $i < $tmp .len; $i ++) {')
|
||||
p.genln('$var_typ $val = (($var_typ *) bytes_$tmp . data)[$i];')
|
||||
p.gen_for_str_header(i, tmp, var_typ, val)
|
||||
}
|
||||
}
|
||||
// `for val in vals`
|
||||
|
@ -3305,7 +3112,11 @@ fn (p mut Parser) for_st() {
|
|||
if !is_arr && !is_str && !is_range {
|
||||
p.error('cannot range over type `$typ`')
|
||||
}
|
||||
p.genln('$typ $tmp = $expr;')
|
||||
if p.is_js {
|
||||
p.genln('var $tmp = $expr;')
|
||||
} else {
|
||||
p.genln('$typ $tmp = $expr;')
|
||||
}
|
||||
// TODO var_type := if...
|
||||
mut var_type := ''
|
||||
if is_arr {
|
||||
|
@ -3327,23 +3138,17 @@ fn (p mut Parser) for_st() {
|
|||
}
|
||||
p.register_var(val_var)
|
||||
i := p.get_tmp()
|
||||
if is_range {
|
||||
p.genln(';\nfor (int $i = $tmp; $i < $range_end; $i++) {')
|
||||
}
|
||||
else {
|
||||
p.genln(';\nfor (int $i = 0; $i < $tmp .len; $i ++) {')
|
||||
}
|
||||
if is_arr {
|
||||
p.genln('$var_type $val = (($var_type *) ${tmp}.data)[$i];')
|
||||
p.gen_for_header(i, tmp, var_type, val)
|
||||
}
|
||||
else if is_str {
|
||||
p.genln('$var_type $val = (($var_type *) ${tmp}.str)[$i];')
|
||||
p.gen_for_str_header(i, tmp, var_type, val)
|
||||
}
|
||||
else if is_range {
|
||||
else if is_range && !p.is_js {
|
||||
p.genln(';\nfor ($i_type $i = $tmp; $i < $range_end; $i++) {')
|
||||
p.genln('$var_type $val = $i;')
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// `for a < b {`
|
||||
p.gen('while (')
|
||||
p.check_types(p.bool_expression(), 'bool')
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue