2020-01-23 23:04:46 +03:00
|
|
|
// Copyright (c) 2019-2020 Alexander Medvednikov. All rights reserved.
|
2019-11-06 23:27:46 +03:00
|
|
|
// 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) for_st() {
|
|
|
|
p.check(.key_for)
|
|
|
|
p.for_expr_cnt++
|
|
|
|
next_tok := p.peek()
|
2019-12-17 17:28:25 +03:00
|
|
|
if p.tok != .lcbr {
|
|
|
|
p.fspace()
|
|
|
|
}
|
2019-12-20 00:29:37 +03:00
|
|
|
// debug := p.scanner.file_path.contains('r_draw')
|
2019-11-06 23:27:46 +03:00
|
|
|
p.open_scope()
|
2019-12-31 21:42:16 +03:00
|
|
|
//mut label := 0
|
2019-11-19 09:53:52 +03:00
|
|
|
mut to := 0
|
2019-11-06 23:27:46 +03:00
|
|
|
if p.tok == .lcbr {
|
|
|
|
// Infinite loop
|
|
|
|
p.gen('while (1) {')
|
|
|
|
}
|
|
|
|
else if p.tok == .key_mut {
|
|
|
|
p.error('`mut` is not required in for loops')
|
|
|
|
}
|
|
|
|
// for i := 0; i < 10; i++ {
|
|
|
|
else if next_tok == .decl_assign || next_tok == .assign || p.tok == .semicolon {
|
|
|
|
p.genln('for (')
|
|
|
|
if next_tok == .decl_assign {
|
2019-11-07 18:45:38 +03:00
|
|
|
p.check_not_reserved()
|
2019-11-06 23:27:46 +03:00
|
|
|
p.var_decl()
|
|
|
|
}
|
|
|
|
else if p.tok != .semicolon {
|
|
|
|
// allow `for ;; i++ {`
|
|
|
|
// Allow `for i = 0; i < ...`
|
|
|
|
p.statement(false)
|
|
|
|
}
|
|
|
|
p.check(.semicolon)
|
|
|
|
p.gen(' ; ')
|
2019-11-09 22:05:44 +03:00
|
|
|
p.fspace()
|
2019-11-06 23:27:46 +03:00
|
|
|
if p.tok != .semicolon {
|
|
|
|
p.bool_expression()
|
|
|
|
}
|
|
|
|
p.check(.semicolon)
|
|
|
|
p.gen(' ; ')
|
2019-11-09 22:05:44 +03:00
|
|
|
p.fspace()
|
2019-11-06 23:27:46 +03:00
|
|
|
if p.tok != .lcbr {
|
|
|
|
p.statement(false)
|
|
|
|
}
|
|
|
|
p.genln(') { ')
|
|
|
|
}
|
|
|
|
// 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];
|
|
|
|
```
|
|
|
|
*/
|
|
|
|
i := p.check_name()
|
|
|
|
p.check(.comma)
|
2019-12-18 10:17:07 +03:00
|
|
|
p.fspace()
|
2019-11-06 23:27:46 +03:00
|
|
|
val := p.check_name()
|
|
|
|
if i == '_' && val == '_' {
|
|
|
|
p.error('no new variables on the left side of `in`')
|
|
|
|
}
|
2019-11-09 22:05:44 +03:00
|
|
|
p.fspace()
|
2019-11-06 23:27:46 +03:00
|
|
|
p.check(.key_in)
|
2019-11-09 22:05:44 +03:00
|
|
|
p.fspace()
|
2019-11-06 23:27:46 +03:00
|
|
|
tmp := p.get_tmp()
|
2019-12-20 00:29:37 +03:00
|
|
|
mut typ,expr := p.tmp_expr()
|
2019-11-06 23:27:46 +03:00
|
|
|
is_arr := typ.starts_with('array_')
|
|
|
|
is_map := typ.starts_with('map_')
|
|
|
|
is_str := typ == 'string'
|
2019-12-20 00:29:37 +03:00
|
|
|
is_variadic_arg := typ.starts_with('varg_')
|
2019-11-06 23:27:46 +03:00
|
|
|
if !is_arr && !is_str && !is_map && !is_variadic_arg {
|
|
|
|
p.error('cannot range over type `$typ`')
|
|
|
|
}
|
|
|
|
if !is_variadic_arg {
|
|
|
|
if p.is_js {
|
|
|
|
p.genln('var $tmp = $expr;')
|
2019-12-20 00:29:37 +03:00
|
|
|
}
|
|
|
|
else {
|
2019-11-06 23:27:46 +03:00
|
|
|
p.genln('$typ $tmp = $expr;')
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// typ = strings.Replace(typ, "_ptr", "*", -1)
|
|
|
|
mut i_var_type := 'int'
|
|
|
|
if is_variadic_arg {
|
|
|
|
typ = typ[5..]
|
|
|
|
p.gen_for_varg_header(i, expr, typ, val)
|
|
|
|
}
|
|
|
|
else if is_arr {
|
2019-12-22 01:44:16 +03:00
|
|
|
typ = parse_pointer(typ[6..])
|
2019-11-06 23:27:46 +03:00
|
|
|
p.gen_for_header(i, tmp, typ, val)
|
|
|
|
}
|
|
|
|
else if is_map {
|
|
|
|
i_var_type = 'string'
|
2019-12-22 01:44:16 +03:00
|
|
|
typ = parse_pointer(typ[4..])
|
2019-11-06 23:27:46 +03:00
|
|
|
p.gen_for_map_header(i, tmp, typ, val, typ)
|
|
|
|
}
|
|
|
|
else if is_str {
|
|
|
|
typ = 'byte'
|
|
|
|
p.gen_for_str_header(i, tmp, typ, val)
|
|
|
|
}
|
|
|
|
// Register temp vars
|
|
|
|
if i != '_' {
|
2019-12-14 19:58:55 +03:00
|
|
|
if p.known_var(i) {
|
|
|
|
p.error('redefinition of `$i`')
|
|
|
|
}
|
2019-12-20 00:29:37 +03:00
|
|
|
p.register_var(Var{
|
2019-11-06 23:27:46 +03:00
|
|
|
name: i
|
|
|
|
typ: i_var_type
|
|
|
|
is_mut: true
|
|
|
|
is_changed: true
|
|
|
|
})
|
|
|
|
}
|
|
|
|
if val != '_' {
|
2019-12-14 19:58:55 +03:00
|
|
|
if p.known_var(val) {
|
|
|
|
p.error('redefinition of `$val`')
|
|
|
|
}
|
2019-12-20 00:29:37 +03:00
|
|
|
p.register_var(Var{
|
2019-11-06 23:27:46 +03:00
|
|
|
name: val
|
|
|
|
typ: typ
|
|
|
|
ptr: typ.contains('*')
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// `for val in vals`
|
2020-01-21 05:22:18 +03:00
|
|
|
else if p.peek() == .key_in || p.peek() == .left_arrow {
|
2020-01-23 23:06:57 +03:00
|
|
|
p.check_not_reserved()
|
2019-11-06 23:27:46 +03:00
|
|
|
val := p.check_name()
|
2019-11-09 22:05:44 +03:00
|
|
|
p.fspace()
|
2020-01-21 05:22:18 +03:00
|
|
|
//p.check(.key_in)
|
|
|
|
p.next()
|
2019-11-06 23:27:46 +03:00
|
|
|
p.fspace()
|
|
|
|
tmp := p.get_tmp()
|
2019-12-20 00:29:37 +03:00
|
|
|
mut typ,expr := p.tmp_expr()
|
2019-11-06 23:27:46 +03:00
|
|
|
is_range := p.tok == .dotdot
|
2019-12-20 00:29:37 +03:00
|
|
|
is_variadic_arg := typ.starts_with('varg_')
|
2019-11-06 23:27:46 +03:00
|
|
|
mut range_end := ''
|
|
|
|
if is_range {
|
|
|
|
p.check_types(typ, 'int')
|
|
|
|
p.check_space(.dotdot)
|
2020-03-06 20:53:29 +03:00
|
|
|
if p.pref.backend == .x64 {
|
2019-11-19 09:53:52 +03:00
|
|
|
to = p.lit.int()
|
|
|
|
}
|
2019-12-20 00:29:37 +03:00
|
|
|
range_typ,range_expr := p.tmp_expr()
|
2019-11-11 05:14:54 +03:00
|
|
|
p.check_types(range_typ, 'int')
|
|
|
|
range_end = range_expr
|
2020-03-06 20:53:29 +03:00
|
|
|
if p.pref.backend == .x64 {
|
2019-12-31 21:42:16 +03:00
|
|
|
//label = p.x64.gen_loop_start(expr.int())
|
2019-12-20 00:29:37 +03:00
|
|
|
// to = range_expr.int() // TODO why empty?
|
2019-12-05 02:11:51 +03:00
|
|
|
}
|
2019-11-06 23:27:46 +03:00
|
|
|
}
|
|
|
|
is_arr := typ.contains('array')
|
2019-12-05 02:11:51 +03:00
|
|
|
is_fixed := typ.starts_with('[')
|
2019-11-06 23:27:46 +03:00
|
|
|
is_str := typ == 'string'
|
2019-12-05 02:11:51 +03:00
|
|
|
if !is_arr && !is_str && !is_range && !is_fixed && !is_variadic_arg {
|
2019-11-06 23:27:46 +03:00
|
|
|
p.error('cannot range over type `$typ`')
|
|
|
|
}
|
|
|
|
if !is_variadic_arg {
|
|
|
|
if p.is_js {
|
|
|
|
p.genln('var $tmp = $expr;')
|
2019-12-20 00:29:37 +03:00
|
|
|
}
|
|
|
|
else if !is_fixed {
|
|
|
|
// Don't copy if it's a fixed array
|
2019-11-06 23:27:46 +03:00
|
|
|
p.genln('$typ $tmp = $expr;')
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// TODO var_type := if...
|
|
|
|
i := p.get_tmp()
|
|
|
|
if is_variadic_arg {
|
|
|
|
typ = typ[5..]
|
|
|
|
p.gen_for_varg_header(i, expr, typ, val)
|
|
|
|
}
|
|
|
|
else if is_range {
|
|
|
|
typ = 'int'
|
|
|
|
p.gen_for_range_header(i, range_end, tmp, typ, val)
|
|
|
|
}
|
|
|
|
else if is_arr {
|
2019-12-22 01:44:16 +03:00
|
|
|
typ = parse_pointer(typ[6..]) // all after `array_`
|
2019-11-06 23:27:46 +03:00
|
|
|
p.gen_for_header(i, tmp, typ, val)
|
|
|
|
}
|
|
|
|
else if is_str {
|
|
|
|
typ = 'byte'
|
|
|
|
p.gen_for_str_header(i, tmp, typ, val)
|
|
|
|
}
|
2019-12-05 02:11:51 +03:00
|
|
|
else if is_fixed {
|
|
|
|
typ = typ.all_after(']')
|
|
|
|
p.gen_for_fixed_header(i, expr, typ, val)
|
|
|
|
}
|
2019-11-06 23:27:46 +03:00
|
|
|
// println('for typ=$typ vartyp=$var_typ')
|
|
|
|
// Register temp var
|
|
|
|
if val != '_' {
|
2019-12-14 19:58:55 +03:00
|
|
|
if p.known_var(val) {
|
|
|
|
p.error('redefinition of `$val`')
|
|
|
|
}
|
2019-12-20 00:29:37 +03:00
|
|
|
p.register_var(Var{
|
2019-11-06 23:27:46 +03:00
|
|
|
name: val
|
|
|
|
typ: typ
|
|
|
|
ptr: typ.contains('*')
|
|
|
|
is_changed: true
|
|
|
|
is_mut: false
|
|
|
|
is_for_var: true
|
|
|
|
})
|
|
|
|
}
|
2019-12-20 00:29:37 +03:00
|
|
|
}
|
|
|
|
else {
|
2019-11-06 23:27:46 +03:00
|
|
|
// `for a < b {`
|
|
|
|
p.gen('while (')
|
|
|
|
p.check_types(p.bool_expression(), 'bool')
|
|
|
|
p.genln(') {')
|
|
|
|
}
|
|
|
|
p.fspace()
|
|
|
|
p.check(.lcbr)
|
2019-11-11 06:06:49 +03:00
|
|
|
p.genln('') // TODO why is this needed?
|
2019-11-06 23:27:46 +03:00
|
|
|
p.statements()
|
|
|
|
p.close_scope()
|
|
|
|
p.for_expr_cnt--
|
|
|
|
p.returns = false // TODO handle loops that are guaranteed to return
|
2019-12-31 21:42:16 +03:00
|
|
|
//if label > 0 {
|
|
|
|
//p.x64.gen_loop_end(to, label)
|
|
|
|
//}
|
2019-11-06 23:27:46 +03:00
|
|
|
}
|
|
|
|
|