`if a := foo() {` syntax for handling optionals
parent
56e4ed1e6b
commit
5ba354fa2c
|
@ -6,6 +6,11 @@ const (
|
||||||
dot_ptr = '->'
|
dot_ptr = '->'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
fn (p mut Parser) gen_or_else(pos int) string {
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
// returns the type of the new variable
|
// returns the type of the new variable
|
||||||
fn (p mut Parser) gen_var_decl(name string, is_static bool) string {
|
fn (p mut Parser) gen_var_decl(name string, is_static bool) string {
|
||||||
// Generate expression to tmp because we need its type first
|
// Generate expression to tmp because we need its type first
|
||||||
|
@ -69,7 +74,7 @@ fn (p mut Parser) gen_fn_decl(f Fn, typ, str_args string) {
|
||||||
p.genln('$dll_export_linkage$typ $fn_name_cgen($str_args) {')
|
p.genln('$dll_export_linkage$typ $fn_name_cgen($str_args) {')
|
||||||
}
|
}
|
||||||
|
|
||||||
// blank identifer assignment `_ = 111`
|
// blank identifer assignment `_ = 111`
|
||||||
fn (p mut Parser) gen_blank_identifier_assign() {
|
fn (p mut Parser) gen_blank_identifier_assign() {
|
||||||
assign_error_tok_idx := p.token_idx
|
assign_error_tok_idx := p.token_idx
|
||||||
p.check_name()
|
p.check_name()
|
||||||
|
|
|
@ -473,10 +473,10 @@ fn (p mut Parser) import_statement() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (p mut Parser) const_decl() {
|
fn (p mut Parser) const_decl() {
|
||||||
if p.tok == .key_import {
|
if p.tok == .key_import {
|
||||||
p.error_with_token_index(
|
p.error_with_token_index(
|
||||||
'`import const` was removed from the language, ' +
|
'`import const` was removed from the language, ' +
|
||||||
'because predeclaring C constants is not needed anymore. ' +
|
'because predeclaring C constants is not needed anymore. ' +
|
||||||
'You can use them directly with C.CONST_NAME',
|
'You can use them directly with C.CONST_NAME',
|
||||||
p.cur_tok_index()
|
p.cur_tok_index()
|
||||||
)
|
)
|
||||||
|
@ -1651,39 +1651,15 @@ fn (p mut Parser) name_expr() string {
|
||||||
}
|
}
|
||||||
return p.expected_type
|
return p.expected_type
|
||||||
}
|
}
|
||||||
// //////////////////////////
|
// Variable, checked before modules, so module shadowing is allowed.
|
||||||
// module ?
|
// (`gg = gg.newcontext(); gg.draw_rect(...)`)
|
||||||
if p.peek() == .dot && ((name == p.mod && p.table.known_mod(name)) ||
|
|
||||||
p.import_table.known_alias(name)) && !is_c &&
|
|
||||||
!p.known_var(name) // Allow shadowing (`gg = gg.newcontext(); gg.foo()`)
|
|
||||||
{
|
|
||||||
mut mod := name
|
|
||||||
// must be aliased module
|
|
||||||
if name != p.mod && p.import_table.known_alias(name) {
|
|
||||||
p.import_table.register_used_import(name)
|
|
||||||
// we replaced "." with "_dot_" in p.mod for C variable names,
|
|
||||||
// do same here.
|
|
||||||
mod = p.import_table.resolve_alias(name).replace('.', '_dot_')
|
|
||||||
}
|
|
||||||
p.next()
|
|
||||||
p.check(.dot)
|
|
||||||
name = p.lit
|
|
||||||
p.fgen(name)
|
|
||||||
name = prepend_mod(mod, name)
|
|
||||||
}
|
|
||||||
else if !p.table.known_type(name) && !p.known_var(name) &&
|
|
||||||
!p.table.known_fn(name) && !p.table.known_const(name) && !is_c
|
|
||||||
{
|
|
||||||
name = p.prepend_mod(name)
|
|
||||||
}
|
|
||||||
// Variable
|
|
||||||
for { // TODO remove
|
for { // TODO remove
|
||||||
|
mut v := p.find_var_check_new_var(name) or { break }
|
||||||
if name == '_' {
|
if name == '_' {
|
||||||
p.error('cannot use `_` as value')
|
p.error('cannot use `_` as value')
|
||||||
}
|
}
|
||||||
mut v := p.find_var_check_new_var(name) or { break }
|
|
||||||
if ptr {
|
if ptr {
|
||||||
p.gen('& /*v*/ ')
|
p.gen('&')
|
||||||
}
|
}
|
||||||
else if deref {
|
else if deref {
|
||||||
p.gen('*')
|
p.gen('*')
|
||||||
|
@ -1716,6 +1692,73 @@ fn (p mut Parser) name_expr() string {
|
||||||
}
|
}
|
||||||
return typ
|
return typ
|
||||||
} // TODO REMOVE for{}
|
} // TODO REMOVE for{}
|
||||||
|
// Module?
|
||||||
|
if p.peek() == .dot && ((name == p.mod && p.table.known_mod(name)) ||
|
||||||
|
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) {
|
||||||
|
p.import_table.register_used_import(name)
|
||||||
|
// we replaced "." with "_dot_" in p.mod for C variable names,
|
||||||
|
// do same here.
|
||||||
|
mod = p.import_table.resolve_alias(name).replace('.', '_dot_')
|
||||||
|
}
|
||||||
|
p.next()
|
||||||
|
p.check(.dot)
|
||||||
|
name = p.lit
|
||||||
|
p.fgen(name)
|
||||||
|
name = prepend_mod(mod, name)
|
||||||
|
}
|
||||||
|
// 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
|
||||||
|
{
|
||||||
|
name = p.prepend_mod(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Variable, checked before modules, so module shadowing is allowed.
|
||||||
|
// (`gg = gg.newcontext(); gg.draw_rect(...)`)
|
||||||
|
for { // TODO remove
|
||||||
|
mut v := p.find_var_check_new_var(name) or { break }
|
||||||
|
if name == '_' {
|
||||||
|
p.error('cannot use `_` as value')
|
||||||
|
}
|
||||||
|
if ptr {
|
||||||
|
p.gen('&')
|
||||||
|
}
|
||||||
|
else if deref {
|
||||||
|
p.gen('*')
|
||||||
|
}
|
||||||
|
if p.pref.autofree && v.typ == 'string' && v.is_arg &&
|
||||||
|
p.assigned_type == 'string' {
|
||||||
|
p.warn('setting moved ' + v.typ)
|
||||||
|
p.mark_arg_moved(v)
|
||||||
|
}
|
||||||
|
mut typ := p.var_expr(v)
|
||||||
|
// *var
|
||||||
|
if deref {
|
||||||
|
if !typ.contains('*') && !typ.ends_with('ptr') {
|
||||||
|
println('name="$name", t=$v.typ')
|
||||||
|
p.error('dereferencing requires a pointer, but got `$typ`')
|
||||||
|
}
|
||||||
|
typ = typ.replace('ptr', '')// TODO
|
||||||
|
typ = typ.replace('*', '')// TODO
|
||||||
|
}
|
||||||
|
// &var
|
||||||
|
else if ptr {
|
||||||
|
typ += '*'
|
||||||
|
}
|
||||||
|
if p.inside_return_expr {
|
||||||
|
//println('marking $v.name returned')
|
||||||
|
p.mark_var_returned(v)
|
||||||
|
// v.is_returned = true // TODO modifying a local variable
|
||||||
|
// that's not used afterwards, this should be a compilation
|
||||||
|
// error
|
||||||
|
}
|
||||||
|
return typ
|
||||||
|
} // TODO REMOVE for{}
|
||||||
|
|
||||||
// if known_type || is_c_struct_init || (p.first_pass() && p.peek() == .lcbr) {
|
// if known_type || is_c_struct_init || (p.first_pass() && p.peek() == .lcbr) {
|
||||||
// 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) {
|
||||||
|
@ -1970,7 +2013,7 @@ fn (p mut Parser) dot(str_typ_ string, method_ph int) string {
|
||||||
//}
|
//}
|
||||||
mut str_typ := str_typ_
|
mut str_typ := str_typ_
|
||||||
p.check(.dot)
|
p.check(.dot)
|
||||||
is_variadic_arg := str_typ.starts_with('...')
|
is_variadic_arg := str_typ.starts_with('...')
|
||||||
if is_variadic_arg { str_typ = str_typ.right(3) }
|
if is_variadic_arg { str_typ = str_typ.right(3) }
|
||||||
mut typ := p.find_type(str_typ)
|
mut typ := p.find_type(str_typ)
|
||||||
if typ.name.len == 0 {
|
if typ.name.len == 0 {
|
||||||
|
@ -3133,6 +3176,14 @@ fn (p mut Parser) get_tmp_counter() int {
|
||||||
return p.tmp_cnt
|
return p.tmp_cnt
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// returns expression's type, and entire expression's string representation)
|
||||||
|
fn (p mut Parser) tmp_expr() (string, string) {
|
||||||
|
p.cgen.start_tmp()
|
||||||
|
typ := p.bool_expression()
|
||||||
|
val := p.cgen.end_tmp()
|
||||||
|
return typ, val
|
||||||
|
}
|
||||||
|
|
||||||
fn (p mut Parser) if_st(is_expr bool, elif_depth int) string {
|
fn (p mut Parser) if_st(is_expr bool, elif_depth int) string {
|
||||||
if is_expr {
|
if is_expr {
|
||||||
//if p.fileis('if_expr') {
|
//if p.fileis('if_expr') {
|
||||||
|
@ -3146,7 +3197,36 @@ fn (p mut Parser) if_st(is_expr bool, elif_depth int) string {
|
||||||
p.fgen('if ')
|
p.fgen('if ')
|
||||||
}
|
}
|
||||||
p.next()
|
p.next()
|
||||||
p.check_types(p.bool_expression(), 'bool')
|
// `if a := opt() { }` syntax
|
||||||
|
if p.tok == .name && p.peek() == .decl_assign {
|
||||||
|
option_tmp := p.get_tmp()
|
||||||
|
var_name := p.lit
|
||||||
|
p.next()
|
||||||
|
p.check(.decl_assign)
|
||||||
|
option_type, expr := p.tmp_expr()// := p.bool_expression()
|
||||||
|
typ := option_type.right(7)
|
||||||
|
// Option_User tmp = get_user(1);
|
||||||
|
// if (tmp.ok) {
|
||||||
|
// User user = *(User*)tmp.data;
|
||||||
|
// [statements]
|
||||||
|
// }
|
||||||
|
p.cgen.insert_before('$option_type $option_tmp = $expr; ')
|
||||||
|
p.check(.lcbr)
|
||||||
|
p.genln(option_tmp + '.ok) {')
|
||||||
|
p.genln('$typ $var_name = *($typ*) $option_tmp . data;')
|
||||||
|
p.register_var(Var {
|
||||||
|
name: var_name
|
||||||
|
typ: typ
|
||||||
|
is_mut: false // TODO
|
||||||
|
//is_alloc: p.is_alloc || typ.starts_with('array_')
|
||||||
|
//line_nr: p.tokens[ var_token_idx ].line_nr
|
||||||
|
//token_idx: var_token_idx
|
||||||
|
})
|
||||||
|
p.statements()
|
||||||
|
return 'void'
|
||||||
|
} else {
|
||||||
|
p.check_types(p.bool_expression(), 'bool')
|
||||||
|
}
|
||||||
if is_expr {
|
if is_expr {
|
||||||
p.gen(') ? (')
|
p.gen(') ? (')
|
||||||
}
|
}
|
||||||
|
@ -3731,7 +3811,8 @@ fn (p mut Parser) return_st() {
|
||||||
}
|
}
|
||||||
p.inside_return_expr = false
|
p.inside_return_expr = false
|
||||||
// Automatically wrap an object inside an option if the function
|
// Automatically wrap an object inside an option if the function
|
||||||
// returns an option
|
// returns an option:
|
||||||
|
// `return val` => `return opt_ok(val)`
|
||||||
if p.cur_fn.typ.ends_with(expr_type) && !is_none &&
|
if p.cur_fn.typ.ends_with(expr_type) && !is_none &&
|
||||||
p.cur_fn.typ.starts_with('Option_') {
|
p.cur_fn.typ.starts_with('Option_') {
|
||||||
tmp := p.get_tmp()
|
tmp := p.get_tmp()
|
||||||
|
|
|
@ -351,12 +351,11 @@ fn (table &Table) known_type(typ_ string) bool {
|
||||||
|
|
||||||
fn (table &Table) known_type_fast(t &Type) bool {
|
fn (table &Table) known_type_fast(t &Type) bool {
|
||||||
return t.name != '' && !t.is_placeholder
|
return t.name != '' && !t.is_placeholder
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (t &Table) find_fn(name string) ?Fn {
|
fn (t &Table) find_fn(name string) ?Fn {
|
||||||
f := t.fns[name]
|
f := t.fns[name]
|
||||||
if !isnil(f.name.str) {
|
if f.name.str != 0 { // TODO
|
||||||
return f
|
return f
|
||||||
}
|
}
|
||||||
return none
|
return none
|
||||||
|
|
|
@ -34,3 +34,11 @@ fn test_option_for_base_type_without_variable() {
|
||||||
println('nice')
|
println('nice')
|
||||||
println(val2)
|
println(val2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn test_if_opt() {
|
||||||
|
if val := err_call(false) {
|
||||||
|
assert val == 42
|
||||||
|
}
|
||||||
|
assert 1 == 1
|
||||||
|
println('nice')
|
||||||
|
}
|
||||||
|
|
|
@ -35,11 +35,10 @@ enum Token {
|
||||||
left_shift
|
left_shift
|
||||||
righ_shift
|
righ_shift
|
||||||
//at // @
|
//at // @
|
||||||
// = := += -=
|
assign // =
|
||||||
assign
|
decl_assign // :=
|
||||||
decl_assign
|
plus_assign // +=
|
||||||
plus_assign
|
minus_assign // -=
|
||||||
minus_assign
|
|
||||||
div_assign
|
div_assign
|
||||||
mult_assign
|
mult_assign
|
||||||
xor_assign
|
xor_assign
|
||||||
|
|
|
@ -8,6 +8,10 @@ module builtin
|
||||||
This is work in progress.
|
This is work in progress.
|
||||||
A very early test version of the hashmap with a fixed size.
|
A very early test version of the hashmap with a fixed size.
|
||||||
Only works with string keys and int values for now.
|
Only works with string keys and int values for now.
|
||||||
|
|
||||||
|
I added this to improve performance of the V compiler,
|
||||||
|
which uses lots of O(log n) map get's. Turned out with N < 10 000
|
||||||
|
the performance gains are basically non-existent.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import math
|
import math
|
||||||
|
|
Loading…
Reference in New Issue