diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index cef9d8c1de..441259d3f0 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -244,9 +244,10 @@ pub mut: pub struct IdentVar { pub mut: - typ table.Type - is_mut bool - is_static bool + typ table.Type + is_mut bool + is_static bool + is_optional bool } pub type IdentInfo = IdentFn | IdentVar diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 7a60821250..6e3d402b8c 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -733,6 +733,7 @@ pub fn (c mut Checker) ident(ident mut ast.Ident) table.Type { ident.kind = .variable ident.info = ast.IdentVar{ typ: typ + is_optional: table.type_is_optional(typ) } return typ } diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index 0659fc0096..5f0f98f74c 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -51,7 +51,7 @@ pub fn (g mut Gen) init() { } // V type to C type -pub fn (g &Gen) typ(t table.Type) string { +pub fn (g mut Gen) typ(t table.Type) string { nr_muls := table.type_nr_muls(t) sym := g.table.get_type_symbol(t) mut styp := sym.name.replace_each(['.', '__']) @@ -65,6 +65,10 @@ pub fn (g &Gen) typ(t table.Type) string { // TODO perf and other C structs styp = 'struct stat' } + if table.type_is_optional(t) { + styp = 'Option_' + styp + g.definitions.writeln('typedef Option $styp;') + } return styp } @@ -264,26 +268,7 @@ fn (g mut Gen) stmt(node ast.Stmt) { } ast.Import {} ast.Return { - g.write('return') - // multiple returns - if it.exprs.len > 1 { - styp := g.typ(g.fn_decl.return_type) - g.write(' ($styp){') - for i, expr in it.exprs { - g.write('.arg$i=') - g.expr(expr) - if i < it.exprs.len - 1 { - g.write(',') - } - } - g.write('}') - } - // normal return - else if it.exprs.len == 1 { - g.write(' ') - g.expr(it.exprs[0]) - } - g.writeln(';') + g.return_statement(it) } ast.StructDecl { name := it.name.replace('.', '__') @@ -621,13 +606,7 @@ fn (g mut Gen) expr(node ast.Expr) { g.write(it.val) } ast.Ident { - name := it.name.replace('.', '__') - if name.starts_with('C__') { - g.write(name[3..]) - } - else { - g.write(name) - } + g.ident(it) } ast.IfExpr { // If expression? Assign the value to a temp var. @@ -798,7 +777,7 @@ fn (g mut Gen) expr(node ast.Expr) { g.write(')') } ast.None { - g.write('0') + g.write('opt_none()') } ast.ParExpr { g.write('(') @@ -965,6 +944,27 @@ fn (g mut Gen) infix_expr(node ast.InfixExpr) { } } +fn (g mut Gen) ident(node ast.Ident) { + name := node.name.replace('.', '__') + if name.starts_with('C__') { + g.write(name[3..]) + } + else { + // TODO `is` + match node.info { + ast.IdentVar { + if it.is_optional { + styp := g.typ(it.typ)[7..] // Option_int => int TODO perf? + g.write('(*($styp*)${name}.data)') + return + } + } + else {} + } + g.write(name) + } +} + fn (g mut Gen) index_expr(node ast.IndexExpr) { // TODO else doesn't work with sum types mut is_range := false @@ -1041,6 +1041,51 @@ fn (g mut Gen) index_expr(node ast.IndexExpr) { } } +fn (g mut Gen) return_statement(it ast.Return) { + g.write('return') + // multiple returns + if it.exprs.len > 1 { + styp := g.typ(g.fn_decl.return_type) + g.write(' ($styp){') + for i, expr in it.exprs { + g.write('.arg$i=') + g.expr(expr) + if i < it.exprs.len - 1 { + g.write(',') + } + } + g.write('}') + } + // normal return + else if it.exprs.len == 1 { + g.write(' ') + // `return opt_ok(expr)` for functions that expect an optional + if table.type_is_optional(g.fn_decl.return_type) { + mut is_none := false + mut is_error := false + match it.exprs[0] { + ast.None { + is_none = true + } + ast.CallExpr { + is_error = true // TODO check name 'error' + } + else {} + } + if !is_none && !is_error { + g.write('opt_ok(') + g.expr(it.exprs[0]) + styp := g.typ(g.fn_decl.return_type)[7..] // remove 'Option_' + g.writeln(', sizeof($styp));') + return + } + // g.write('/*OPTIONAL*/') + } + g.expr(it.exprs[0]) + } + g.writeln(';') +} + fn (g mut Gen) const_decl(node ast.ConstDecl) { for i, field in node.fields { name := field.name.replace('.', '__') diff --git a/vlib/v/table/atype_symbols.v b/vlib/v/table/atype_symbols.v deleted file mode 100644 index 657ffda581..0000000000 --- a/vlib/v/table/atype_symbols.v +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright (c) 2019-2020 Alexander Medvednikov. All rights reserved. -// Use of this source code is governed by an MIT license -// that can be found in the LICENSE file. -module table - diff --git a/vlib/v/table/modules.v b/vlib/v/table/modules.v deleted file mode 100644 index 863ad435bc..0000000000 --- a/vlib/v/table/modules.v +++ /dev/null @@ -1,18 +0,0 @@ -module table - -import os - -// Once we have a module format we can read from module file instead -// this is not optimal -pub fn (table &Table) qualify_module(mod string, file_path string) string { - for m in table.imports { - if m.contains('.') && m.contains(mod) { - m_parts := m.split('.') - m_path := m_parts.join(os.path_separator) - if mod == m_parts[m_parts.len - 1] && file_path.contains(m_path) { - return m - } - } - } - return mod -} diff --git a/vlib/v/table/table.v b/vlib/v/table/table.v index a1d34fe760..6026e9c557 100644 --- a/vlib/v/table/table.v +++ b/vlib/v/table/table.v @@ -5,6 +5,7 @@ module table import ( strings + os ) pub struct Table { @@ -60,7 +61,7 @@ pub fn (t mut Table) register_global(name string, typ Type) { // mod: p.mod // is_mut: true // idx: -1 - + } } @@ -494,3 +495,18 @@ pub fn (t &Table) check(got, expected Type) bool { } return true } + +// Once we have a module format we can read from module file instead +// this is not optimal +pub fn (table &Table) qualify_module(mod string, file_path string) string { + for m in table.imports { + if m.contains('.') && m.contains(mod) { + m_parts := m.split('.') + m_path := m_parts.join(os.path_separator) + if mod == m_parts[m_parts.len - 1] && file_path.contains(m_path) { + return m + } + } + } + return mod +}